Membership.ValidateUser returns false on first call - asp.net-mvc

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!

Related

Cannot login via username

I'm trying to login via UserName using PasswordSignInAsync but the result is even False, this is my code:
public async Task<IActionResult> Login(LoginViewModel vm)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(vm.Email);
var result = await _signInManager.PasswordSignInAsync(user.UserName, vm.Password, vm.RememberMe, false);
if (result.Succeeded)
{
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "Wrong Credentials!");
return View(vm);
}
return View(vm);
}
so essentially in my View I fill the email and password fields, and the user object is correctly filled with this information:
UserName = "some_username";
Email = "foo#gmail.com";
I tried to pass both UserName and Email in the first paramter of PasswordSignInAsync but I'm not able to fix this.
I saw also other similar question here, but I don't understand how can I fix this.
Your code is fine. Though, since you are already fetching the user, you can just use that directly:
await _signinManager.PasswordSignInAsync(user, vm.Password, vm.RememberMe, false);
It's important to realize that this method can fail for multiple reasons, not just a bad username/password. 2FA may be required (result.RequiresTwoFactor) or the user could be locked out (result.IsLockedOut). Additionally, if you've required email verification, all login attempts will fail until the email is verified (result.IsNotAllowed). You should be checking for all these conditions and handling each appropriately.

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.

Form Authentication IsOnline method does not retrieve the correct status

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...

Check User.Identity.IsAuthenticated in ActionFilter right after login

I'm basically using the AccountController from the ASP.NET MVC samples. It uses FormsAuthentication to handle the user login. Just to be sure, here is the code to handle user login:
public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
{
if (!ValidateLogOn(userName, password))
{
return View();
}
FormsAuth.SignIn(userName, rememberMe);
//Session["userId"] = 1;
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
As you can see from the commented line, I would like to set a Session variable in this method. However, I figured that it is not the most elegant way of setting a Session variable directly in the controller. It's also inconvenient when unit testing this method (although I could mock it, sure, but still).
So, I figured, I create a custom ActionFilterAttribute that runs after this login routine. If login is succesful, set the session variable in this custom attribute. The code for this is:
public class SetSessionAttribute : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext resultContext)
{
if (resultContext.HttpContext.User.Identity.IsAuthenticated)
{
resultContext.HttpContext.Session["userId"] = 1;
}
base.OnResultExecuted(resultContext);
}
}
The problem is that User.Identity.IsAuthenticated always returns false until the next "page load". I'm overriding OnResultExecuted as I gather that it is the last method to be called in the page lifecycle, but no luck. I also tried OnActionExecuting, OnActionExecuted and OnResultExecuting, but it is always false.
Is there an elegant solution around this? Or should I give up and set the session variable in the controller directly?
I had a similar problem with log out because User.Identity.IsAuthenticated was true until next page request but I needed a way to know if user is really finished work with an application.
I think you should set Session or ViewData variable in controller or pass it to another controller via routeValues.

Resources