You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET更新用户数据时NormalizedUsername变更致登录失败问题

问题分析与解决方案

核心问题原因

你遇到的登录失败,本质是ASP.NET Identity的登录逻辑匹配字段不匹配:

  • 你在登录时将输入的邮箱转成大写,传给PasswordSignInAsync(string userName, ...)方法,这个方法默认通过NormalizedUserName字段查找用户。
  • 但启用2FA或通过脚手架更新用户后,NormalizedUserName被更新为用户名的大写形式(比如用户trisha的NormalizedUserName变成了TRISHA),而你传入的是大写邮箱TEST3@EXAMPLE.NET,两者不匹配,导致登录失败。

解决方案

方案1:修改登录逻辑,直接通过邮箱验证登录

放弃使用PasswordSignInAsync(string userName, ...),改为先通过邮箱定位用户,再用用户对象完成登录验证,绕开NormalizedUserName的匹配限制:

修改你的OnPostAsync方法:

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl ??= Url.Content("~/");

    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

    if (ModelState.IsValid)
    {
        // 先通过邮箱查找用户
        var user = await _userManager.FindByEmailAsync(Input.Email);
        if (user == null)
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }

        // 使用用户对象进行密码验证和登录
        var result = await _signInManager.PasswordSignInAsync(user, Input.Password, Input.RememberMe, lockoutOnFailure: false);
        
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }
    return Page();
}

方案2:确保NormalizedUserName与NormalizedEmail始终同步

从根源上让两个字段保持一致,避免后续出现匹配问题:

  1. 用户创建阶段:注册用户时,将UserName设置为邮箱,这样NormalizedUserName会自动与NormalizedEmail同步:
// 注册示例代码
var user = new USUARIO 
{ 
    UserName = Input.Email, 
    Email = Input.Email, 
    NOMBRE = Input.Nombre, 
    APELLIDO = Input.Apellido 
};
var result = await _userManager.CreateAsync(user, Input.Password);
  1. 用户更新阶段:当通过脚手架或代码更新用户时,手动同步字段值:
// 比如启用2FA后同步字段
user.NormalizedUserName = user.NormalizedEmail;
await _userManager.UpdateAsync(user);

也可以重写UserManager的UpdateAsync方法,实现每次更新用户时自动同步两个字段,彻底避免手动操作遗漏。


内容的提问来源于stack exchange,提问作者Rodrigo Villanueva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 17:52:37