Cannot login on ASP.NET Identity 2 site after prog

2019-03-12 22:41发布

问题:

I have a new MVC 5 razor, EF 6 web application using ASP.NET Identity 2 for the membership system. When I create the users manually using the Register link on the web page, it goes fine. I can create the user, I can then login with the given password and then logout.

I don't know how to use the database initializer with migration for Identity 2, there are countless examples with Identity 1 and other alpha and beta versions which only serve to confuse people. Since I don't know that yet, I use a temporary MVC view to install the membership.

I see the the view executes properly, I see the users and roles as well as the associations of users with roles in the database. I also see that the users have a hashed password in the record.

However, after doing that I cannot login to the identity system (local) with the plain text passwords I used in the Create method, why? BTW I have omitted the try/catch and checks for user and role creations (they execute without error).

DbContext ctx = ApplicationDbContext.Create();
transaction = ctx.Database.BeginTransaction();
RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(ctx));
var roleAdmin = roleManager.Create(new IdentityRole("Admin"));

var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(ctx));
ApplicationUser userAdmin = new ApplicationUser { Id = "admin", Email = "me@there.com", UserName = "admin" };
            userManager.Create(userAdmin, "Test_2013");
userManager.AddToRole(userAdmin.Id, "Admin");
userManager.Update(userAdmin);

transaction.Commit(); 

So after that if I attempt to login to the account with the email address and the Test_2013 password I get an error indicating the username/password is incorrect.

回答1:

After much investigations on the actual database (Identity 2) and the web I came to the conclusion nobody knew :) In fact of the millions of sites that have outdated information about Identity and even place Identity 2.0 code that is already outdated I had to dig into it further with the SQL Profiler and the SQL Management Studio.

In Identity 2.0 there is an Id property that is an nvarchar() but actually contains a Guid. I wonder why Microsoft didn't just made it a uniqueidentifier type?! I was setting this property when I should have left it alone (let it autogenerate it).

Likewise in Identity 2.0 there is an UserName field which I was populating with the username. It seems UserName should be the same as Email, otherwise attempts to login will simply fail.



回答2:

I also faced this stressing issue. It has to be with the default Login method created in the AccountsController:

 public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

You can see that

"await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);"

is including the Email as the first parameter, but if you check the definition for PasswordSignInAsync you will see that it MUST receive the Username as first parameter and not the Email.

It works by default because the method for Registering a New User sets both properties (Username and Email) equals to the user provided email value. But if you saved a new user programatically and set Username and Email to different values, Login will fail.

This is by all means an error from --> MS <--"I trusted those guys and spent several hours trying to make it work, until I doubted about them"

So you know now what to do: 1)Change your login method to pass username as first argument ir change Register method to save username and email with different values. I hope it helps someone else.



回答3:

There is a mistake in the LoginViewModel. If you look at the Login method (post version), the first parameter of the PasswordSignInAsync method should be the username, but in the loginViewModel we have the email instead.

Obviously, you cannot make it work properly, because PasswordSignInAsync is actually considering the first parameter as the username, and not the email address, and there is an email validator For the Email property in the LoginViewModel.

You have to rename the Email Property of the LoginViewModel to UserName for example, and remove the EmailAddress annotation.

Then in the corresponding login view, you have to replace the email input field and use the UserName instead.

Then in the login method in the AccountController, you use the model.UserName as the first parameter, and it should work correctly now.