Form Authentication IsOnline method does not retrieve the correct status - asp.net-mvc

I am using Form Authentication in an ASP.NET MVC project.
When the current user click on the Exit link the code execute an action that does in sequence:
System.Web.Security.FormsAuthentication.SignOut();
Session.Abandon();
The second call is not properly needed because I am not using session at all.
The problem is that if I login with an Admin account I can see the user still Logged In.
Where I am doing wrong?
thanks for helping!
EDIT:
Added the Login code just to be complete
if (ModelState.IsValid) {
if (MembershipService.ValidateUser(model.UserName, model.Password)) {
System.Web.Security.FormsAuthentication.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl)) {
return Redirect(returnUrl);
}
else {
return RedirectToAction("Index", "Home");
}
}
else {
ModelState.AddModelError("", "Error....");
}
}

Ok. I have found the problem.
I was using, to show the current loggein users the following call
MembershipUser user = Membership.GetUser(userKey, true)
if ( user.IsOnline ) {
...
}
and I have realized that the second parameter of the GetUser method sets the User status to online and updates the LastActivity field in the data store.
I dont know why this is working this way but that's it...

Related

ASP NET MVC5 randomly redirects to my login page

I have an ASP.NET MVC application with ActionFilters for Authentication and no Forms Authentication. "SegurancaAction" is the attribute responsible for validating authentication and exists in every controller endpoint except in the login ones (as expected).
I'm facing a problem in which sometimes I try to access one of my controllers and the GET request goes to my login endpoint. In the method Application_BeginRequest at Global.asax, I can see the very first attempt is at 'security/login' (the route to my login endpoint) instead of the one I want. I can also see this endpoint being called in debugging apps such as Fiddler, or ASP.NET Trace or Glimpse MVC5.
Besides calling the wrong action, once I login again this issue keeps happening for the same endpoint I was trying to access, redirecting my site to the login page over and over.
SegurancaAction:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Autenticacoes autenticacao = _authApp.IsAutenticado(filterContext.HttpContext.Session.SessionID);
if (autenticacao == null)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.Unauthorized);
else
{
filterContext.HttpContext.Response.RedirectPermanent("/security/login");
return;
}
}
else
{
// other stuff
}
}
SecurityController:
[HttpPost]
[ConfigAction]
public ActionResult Login(vm_Login login)
{
if (ModelState.IsValid)
{
if (!String.IsNullOrEmpty(login.Login) && !String.IsNullOrEmpty(login.Senha))
{
Entidades entidade = _entidadeApp.GetByUsuarioSenha(login.Login, login.Senha);
if (entidade == null)
{
ViewBag.FalhaAutenticacao = "As credenciais informadas não conferem!";
return View("Login");
}
else
{
string encryptionKey = System.Configuration.ConfigurationManager.AppSettings["EncryptionKey"];
var a = _autenticacaoApp.Autenticar(entidade.Id, encryptionKey, login.Senha, HttpContext.Session.SessionID);
}
Response.RedirectPermanent("~/principal/index");
}
}
else
{
ViewBag.FalhaAutenticacao = "É necessário informar o usuario e a senha!";
}
return View();
}
All _autenticacaoApp.Autenticar(...) method does is to create an authentication entry on the database, it's a completely custom code.
Does anyone know why this issue happens? Sometimes I can reproduce it by deleting the cookies that contain ASP.NET_Session ID and RequestVerificationToken. So far I know those cookies are automatically generated and I notice that sometimes when I login again they are not re-generated.
I figured out the issue. It was this "RedirectPermanent" method being used here:
filterContext.HttpContext.Response.RedirectPermanent("/security/login");
It tells the browser that the resource I'm trying to access is no longer available and is now located at this new Url. The browser records this information and always redirects to the new resource.
I just changed it to use "Redirect" instead.

Membership.ValidateUser returns false on first call

I have a bit of a peculiar problem which I don't really understand..
For my login I am using the following method:
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.RedirectFromLoginPage(model.UserName, model.RememberMe);
return Redirect("/");
}
ModelState.AddModelError("", Resources.Global.IncorrectUserName);
}
// If we got this far, something failed, redisplay form
return PartialView(model);
}
The weird thing is that on the first login attempt the secont if statement (Membership.ValidateUser) returns false. At the second attempt it returns true and the user gets access to the application.
I have found similar questions, but none of the answers there have worked for me.. :(
What I now would like to know is:
1: why does this happen?
2: How can I correct this so that the user gets logged in at the first attempt?
Thanks!

Updating Twitter status using LinqToTwitter

here's what set out to do:
Make an MVC app on which the user clicks a button and is taken to the Twitter login page
After giving the credentials the user is redirected to a second page
On the secong page there is a text box and a 'Tweet' button
Entering a message and clicking on 'Tweet' will update the status
I got till the 2nd point by following the samples from LinqToTwitter codeplex page.
The code from OAuth controller works fine and it does redirect back to MVC app's second page.
But I am missing something which is not posting the status.
This is the code in the button click from which I pass the user entered status:
public ActionResult Status(string status)
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
auth.CompleteAuthorizeAsync(Request.Url);
var twitterContext = new TwitterContext(auth);
TweetAsync(twitterContext, status);
return View(); //return some view to the user
}
void TweetAsync(TwitterContext twitterCtx, string statusToUpdate)
{
var tweet = twitterCtx.TweetAsync(statusToUpdate);
if (tweet != null)
{
// Inform the user about success
}
}
Both the above methods are also in OAuth controller.
Can someone please help me with this?
Thanks in advance.
Change your method to use async and return a Task:
public async Task Status(string status)
{
//...
var tweet = await twitterContext.TweetAsync(twitterContext, status);
// ...
}
and then await TweetAsync, assigning the response to a Status entity named tweet. If you want a separate method for calling TweetAsync, make that async also. With async, you must make every method in the call chain async.

MVC Url not pathing correctly

I have a link going to
<a class="k-link" href="/UserView/EditByName?UserName=MVCTest6">Profile</a>
When the link it is clicked it goes to this
URL: http://localhost:3256/MVCTest6/Create
which works when i am logged in as an admin user. (The folder has no security in a web.config setting it apart). This link actually works on another part of the page.
The user also already exist and has been authenticated.
Can this please be explained?
I get it ! This is where the problem is,
return RedirectToAction("Create", User.Identity.Name);
you are using this overload RedirectToAction("Action", "Contoller");
So the later part is taken as the controller. Try other overloads that matches your requirement, if you are trying to pass values to another action, which must be like
return RedirectToAction("Create", new {UserName = User.Identity.Name});
I forgot I had logic in place to redirect if user profile was not created. This was causing the problem. My test user didnt have profile already setup so it was redirecting to the create page
public ActionResult EditByName(string userName)//EditByName
{
if (User.Identity.IsAuthenticated)
{
UserModel usermodel = repository.Get(User.Identity.Name);// db.UserModels.Find(id);
if (usermodel == null)
{
return RedirectToAction("Create", User.Identity.Name);
}
return View(usermodel);
}
else { return RedirectToAction("Login", controllerName: "AccountView"); }
}

Pass Value from View To Controller in Asp.net MVC

I am trying to pass a message to another view (actually same controller) I can do it well but there is a problem for me..
I am new on web and it doesnt seem good ..
and here my c# code
if (createStatus == MembershipCreateStatus.Success)
{
string registrationMessage = "You have registered successfully";
return RedirectToAction("KurumsalGiris", new { message = registrationMessage });
}
[AllowAnonymous] //sonradan eklendi
public ActionResult KurumsalGiris(string message="")
{
if (User.Identity.IsAuthenticated)
return Content("Zaten giriş yapmışsınız");
ViewBag.RegistrationMessage = message;
return View();
}
and here html side
#model E_Cv.Models.LogOnModel
#{
ViewBag.Title = "Kurumsal Giriş";
}
<h2>Kurumsal Giriş</h2>
<h2>#ViewBag.RegistrationMessage</h2>
<p>
Please enter your user name and password.
#Html.ActionLink("Yeni Kurum Kaydı", "KurumsalKayit")
if you don't have an account.
</p>
so I dont know how to pass value to another view with different way.. I dont want to show this kind of message on address bar and user musnt change it.
Secondly Could I do it with "Get" Method?
Why don't you just return a different view rather than redirecting? In fact, the code the posted in the first place should be posting to a controller that returns a view for a successful login.
In fact, why are you redirecting to a page that asks the user to login if they've just logged in?
Other possible options include encrypting the string in the URL, or just passing a flag in the URL that the controller translates into the corresponding string.
What you would do is instead of returning a RedirectToAction
you could return the View directly: (second parameter is a model, where you can use the same model class E_Cv.Models.LogOnModel adding a RegistrationMessage property to it)
return View("<name of the view>",
new E_Cv.Models.LogOnModel {
RegistrationMessage = "You have registered successfully"
});
or keep the data in the ViewBag like you have done:
ViewBag.RegistrationMessage = "You have registered successfully";
return View("<name of the view>");
regarding your last question, give the message is showing in your URL, you are using the GET method, if you return a View instead of a redirect, it'll avoid showing anything in the URL
You should use TempData in this scenario
if (createStatus == MembershipCreateStatus.Success)
{
TempData["Message"] = "You have registered successfully";
return RedirectToAction("KurumsalGiris");
}
And then in your view
#if (TempData["Message"] != null)
{
<h2>#TempData["Message"]</h2>
}
Or if you want to do it in the controller, just keep your view the same as it is at the moment and set ViewBag.RegistrationMessage in the controller
ViewBag.RegistrationMessage = TempData["Message"];
If the question is how to pass data between controllers without using the querystring, then one option is the Session object.
if (createStatus == MembershipCreateStatus.Success)
{
Session["Message"] = "You have registered successfully";
return RedirectToAction("KurumsalGiris");
}
[AllowAnonymous] //sonradan eklendi
public ActionResult KurumsalGiris(string message="")
{
if (User.Identity.IsAuthenticated)
return Content("Zaten giriş yapmışsınız");
ViewBag.RegistrationMessage = (string) Session["Message"];
return View();
}
However, I agree with #Jonathan Wood below that this is not necessarily the best approach to the particular problem you are attempting to solve. Still, as a general technique, it is worth knowing about.

Resources