Asp.net core 支持在ASP.NET Core中使用电子邮件或用户名登录同一用户

Asp.net core 支持在ASP.NET Core中使用电子邮件或用户名登录同一用户,asp.net-core,asp.net-identity,Asp.net Core,Asp.net Identity,我使用ASP.NET核心标识(2.0)和所有默认代码。我更改了AccountController.Login方法以检查旧数据库,并在找不到用户时迁移用户。因为那个旧数据库既有用户名又有电子邮件,所以我在新创建的用户中填充这两个字段 但是,如果我尝试使用迁移的用户再次登录,则使用电子邮件无法工作,因为SQL请求似乎总是只查找其中u.NormalizedUserName=@\u\u NormalizedUserName\u 0 如何使具有不同电子邮件和用户名的单个用户能够使用其用户名或电子邮件登录?

我使用ASP.NET核心标识(2.0)和所有默认代码。我更改了
AccountController.Login
方法以检查旧数据库,并在找不到用户时迁移用户。因为那个旧数据库既有用户名又有电子邮件,所以我在新创建的用户中填充这两个字段

但是,如果我尝试使用迁移的用户再次登录,则使用电子邮件无法工作,因为SQL请求似乎总是只查找
其中u.NormalizedUserName=@\u\u NormalizedUserName\u 0


如何使具有不同电子邮件和用户名的单个用户能够使用其用户名或电子邮件登录?

您可以使用
用户管理器中的
CheckPasswordAsync(用户,密码)
方法:

在调用该方法之前,您可以通过以下方式获取用户:

 var user = await _userManager.FindByNameAsync(userName) ?? await _userManager.FindByEmailAsync(userName);

根据您当前的
UserStore
实现,您可能需要调整
FindByNameAsync
findbyemailsync
或两者兼而有之。

感谢所有贡献者,但我认为这个问题应该得到更准确的答案

ASP.NET核心标识的默认模板将始终创建电子邮件和用户名均包含相同值的用户。然后,默认登录处理程序(在登录视图的
AccountController.login
OnPostAsync
方法中)将始终使用“email”字段作为用户名,并调用
PasswordSignInAsync
。虽然代码似乎暗示它支持电子邮件,但该方法实际上只接受用户名。更令人困惑的是,视图正在验证您输入的电子邮件是否有效,但您输入的内容最终将在
NormalizedUserName
字段中搜索

因此,如Mark和Razvan所述,如果您也希望允许电子邮件,您可以使用
\u userManager.findbyemailsync
获取试图登录的用户的实际用户名,然后使用用户名调用
PasswordSignInAsync

As:“不,你是对的。在注册过程中,模板的用户名和电子邮件是相同的,但无法保持同步。2.2版计划了修复这一糟糕局面的工作。”

悬而未决的问题

  • 您必须更改AccountViewModel.cs

    public class LoginViewModel
        {
            [Required]
            [Display(Name = "Логин/Email")]
            //[EmailAddress]
            public string Email { get; set; }
    
            [Required]
            [DataType(DataType.Password)]
            [Display(Name = "Пароль")]
            public string Password { get; set; }
    
            [Display(Name = "Запомнить меня")]
            public bool RememberMe { get; set; }
        }
    
  • AccountController.cs

    
    公共异步任务登录(LoginView模型,字符串返回URL)
    {
    如果(!ModelState.IsValid)
    {
    返回视图(模型);
    }

    应用程序用户; if(model.Email.Contains(“@”)) user=UserManager.FindByEmail(model.Email); 其他的 user=UserManager.FindByName(model.Email); var result=await-SignInManager.PasswordSignInAsync(user.UserName、model.Password、model.RememberMe、shouldllockout:false); 开关(结果) { 案例标志状态成功: 返回重定向到本地(returnUrl); 案例标志状态锁定输出: 返回视图(“锁定”); 案例标志状态。要求验证: return RedirectToAction(“SendCode”,new{ReturnUrl=ReturnUrl,RememberMe=model.RememberMe}); 案例信号状态故障: 违约: ModelState.AddModelError(“,”和“,”和“); 返回视图(模型); } }

  • 中描述了一种技术。该技术解决了验证视图所需的更改,但并未解决上述问题。使用用户名创建的用户可以使用用户名登录。使用电子邮件创建的用户可以使用电子邮件登录,但同时具有这两个(不同值)的用户将无法使用电子邮件登录。我不确定您所说的是否正确。代码可以使用用户名或电子邮件登录,即使它们不同。前者将直接进入
    PasswordSignInAsync()
    ,但如果使用电子邮件(由@symbol检测),则使用
    findbyemailsync()
    对用户名进行中间查找。然后我们使用的模板就过时了。我看到的对FindByEmailAsync的唯一调用是ForgotPassword和ResetPassword。这是在脚手架2.1控制器中吗?我们的是用2.0生成的。
    
    public async Task Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

    ApplicationUser user; if (model.Email.Contains("@")) user = UserManager.FindByEmail(model.Email); else user = UserManager.FindByName(model.Email); var result = await SignInManager.PasswordSignInAsync(user.UserName, 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("", "Неудачная попытка входа."); return View(model); } }