ASP.NET Core MVC Identity框架登录验证用户名而非邮箱问题排查
问题原因 & 解决方案
核心原因
你调用的PasswordSignInAsync(string userName, string password, ...)重载,第一个参数是要匹配的用户名(UserName字段),而非邮箱。哪怕你把变量名改成Email,底层逻辑依然是去AspNetUsers表中查找UserName等于该参数值的用户。现在你的用户表中UserName和Email是独立的,传入邮箱自然找不到匹配的用户,导致登录失败;而传入用户名时,参数和UserName字段匹配,所以验证通过。
解决方案
要支持邮箱登录,你需要先通过邮箱找到对应用户,再验证密码并完成登录,有两种常用方式:
方式1:支持邮箱/用户名双登录(推荐)
在Login.cshtml.cs的OnPostAsync方法中,先尝试通过邮箱查找用户,找不到再尝试用户名,验证密码后登录:
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); if (ModelState.IsValid) { // 优先通过邮箱查找用户 var user = await _userManager.FindByEmailAsync(Input.Email); // 如果邮箱没找到,尝试按用户名查找(可选,实现双登录) if (user == null) { user = await _userManager.FindByNameAsync(Input.Email); } if (user != null) { // 验证密码是否正确 var isPasswordValid = await _userManager.CheckPasswordAsync(user, Input.Password); if (isPasswordValid) { await _signInManager.SignInAsync(user, Input.RememberMe); _logger.LogInformation("User logged in."); return LocalRedirect(returnUrl); } } // 登录失败,添加错误提示 ModelState.AddModelError(string.Empty, "Invalid login attempt."); }
方式2:修改登录逻辑直接用邮箱验证
如果你只想支持邮箱登录,可以简化逻辑,直接通过邮箱找用户后验证:
if (ModelState.IsValid) { var user = await _userManager.FindByEmailAsync(Input.Email); if (user != null && await _userManager.CheckPasswordAsync(user, Input.Password)) { await _signInManager.SignInAsync(user, Input.RememberMe); _logger.LogInformation("User logged in."); return LocalRedirect(returnUrl); } ModelState.AddModelError(string.Empty, "Invalid login attempt."); }
额外说明
- 确保你的AspNetUsers表中Email字段是唯一的,可以在Program.cs中配置Identity选项开启:
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); // 强制邮箱唯一 builder.Services.Configure<IdentityOptions>(options => { options.User.RequireUniqueEmail = true; });
内容的提问来源于stack exchange,提问作者M.Jafar
相关产品推荐
相关产品推荐

