UserManager.CheckPasswordAsync与SignInManager.PasswordSignInAsync的区别

39

使用ASP.NET Core身份验证 - 当用户提供密码和用户名来获取JWT令牌时,他们将其凭据发布到/api/token

我的token控制器方法是否应该使用UserManager来使用CheckPasswordAsync检查密码,如果通过则返回token,还是应该使用SignInManager并调用PasswordSignInAsync,然后根据该结果返回token?

我看过两种方法的示例,并想知道每种方法的好处,哪种方法更好?

目前,我的团队中有人编写了以下内容:

[AllowAnonymous]
[HttpPost]
public async Task<ActionResult<User>> Post([FromBody]User model)
{
    try
    {                                              
        var user = await _userManager.FindByNameAsync(model.Username);
        if (user == null)
            return StatusCode(StatusCodes.Status401Unauthorized, "Incorrect username or password");

        var passwordOK = await _userManager.CheckPasswordAsync(user, model.Password);
        if (!passwordOK)
            return StatusCode(StatusCodes.Status401Unauthorized, "Incorrect username or password");

        model.Id = user.Id;
        model.Name = user.DisplayName;
        model.Password = "";               

        int expiresIn;
        long expiresOn;
        model.Token = _authorisationService.GetJWTToken(model.Username, user.Id, out expiresIn, out expiresOn);
        model.ExpiresIn = expiresIn;
        model.ExpiresOn = expiresOn;

        return model;
    }
    catch (Exception)
    {
        // log the exception
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
}

但我认为其中有些内容是不必要的。

2个回答

67
您提到的两种方法具有不同的用途:

1. UserManager.CheckPasswordAsync

此方法将提供的密码进行哈希处理并与现有密码哈希值(例如在数据库中存储)进行比较。

2. SignInManager.PasswordSignInAsync

此方法做了更多事情。以下是大致的分解:

  • 检查是否允许登录。例如,如果用户必须确认电子邮件才能登录,则该方法返回SignInResult.Failed
  • 调用UserManager.CheckPasswordAsync以检查密码是否正确(如上所述)。
    • 如果密码不正确且支持锁定,则此方法跟踪失败的登录尝试。如果超过配置的失败登录尝试次数,则锁定用户。
  • 如果用户启用了双因素身份验证,则该方法设置相关的cookie并返回SignInResult.TwoFactorRequired
  • 最后,执行登录过程,生成一个ClaimsPrincipal并通过cookie进行持久化。

如果您不想要确认电子邮件、锁定等功能,则使用像问题中所述的UserManager.CheckPasswordAsync即可。


5
谢谢。经过进一步研究,我发现SigninManager与cookie身份验证有关。如果不想使用cookies,根据GitHub身份验证源代码,我应该避免使用SigninManager。因此,在没有cookie的API中要拥有锁定等功能,我需要自己实现这些功能。 - JimmyShoe
7
@JimmyShoe,你有可以分享的示例代码或者实现示例的链接吗?我的项目中使用的是JWT(而不是cookies),我很惊讶为什么这样的代码这么难找到。请帮我看看。 - lonix
UserManager.CheckPasswordAsync还有一个功能:如果密码不正确,它会记录一条警告信息。这可能会让日志变得混乱,因为我们希望用户偶尔会输错密码,而不希望看到大量的警告信息。 - Dana
.NET Framework 4.6.2是否支持PasswordSignInAsync? - megalucio

0
我对此的简单理解是,我仍然需要使用SignInManager.PasswordSignInAsync来获得其提供的增强功能,但不想调用IsTwoFactorClientRememberedAsync,因为它会创建一个身份验证cookie(我的具体用例是将ASP.NET Core Identity封装在REST API外观中,出于架构原因)。
因此,我简单地创建了一个自定义类,该类派生自SignInManager,并特别重写了Task CheckPasswordSignInAsync(TUser user, string password, bool lockoutOnFailure)方法,这样我就可以有效地重新实现该方法,就像在原始源代码(https://github.com/dotnet/aspnetcore/blob/main/src/Identity/Core/src/SignInManager.cs)中一样,但是没有调用IsTwoFactorClientRememberedAsync。
对我来说似乎工作得不错。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接