I'm use mvc core 3.1 with Identity 3.1.2, with default built-in UI:
services.AddIdentity<IdentityUser, IdentityRole>(opt =>
{
opt.User.RequireUniqueEmail = true;
opt.SignIn.RequireConfirmedEmail = false;
opt.SignIn.RequireConfirmedAccount = false;
}).AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
I wrote hard code that creates initial administrator user:
var userAdminExists = await _userManager.FindByNameAsync("Admin");
if (userAdminExists == null)
{
var user = new IdentityUser
{
Id = Guid.NewGuid().ToString(),
UserName = "Admin",
Email = "xxxxxx@gmail.com",
EmailConfirmed = true
};
var x = await _userManager.CreateAsync(user, _IConfiguration.GetValue<string>("defaultAdminPassword"));
await _userManager.AddToRoleAsync(user, "AdminRole");
}
(Of course I also tried to write the literal password inside the code, for those wondering about the IConfiguration, and I also watched the entries at break-points and everything worked as planned).
the user is created, but when i login with this email address and password in the browser i get "Invalid login attempt." (in normal response, status 200). I wrote test code:
var pass = _configuration.GetValue<string>("defaultAdminPassword");
var res = await _userManager.CheckPasswordAsync(await _userManager.FindByEmailAsync("xxxx@gmail.com"), pass);
And of course it return true...
furthermore, also if i reset password via email reset link ("Forgot your password?") and i set new password, is not work...
but new users created through the "Register" UI interface, work great.
What am I missing?
When you use the Identity UI to sign in, you end up calling SignInManager.PasswordSignInAsync
:
public virtual Task<SignInResult> PasswordSignInAsync( string userName, string password, bool isPersistent, bool lockoutOnFailure);
As you can see from this signature, the first parameter is userName
. When you use the UI as you've described, you provide the email address where the userName is expected. However, when you call FindByEmailAsync
and pass the result into CheckPasswordAsync
, you find the user based on Email
and not UserName
, which works.
When you register a new user using the Identity UI, you end up running this code:
await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
As you can see, this sets both the UserName
and the Email
to Input.Email
. This is why you are able to sign in with these accounts.