ASP.NET Core Identity - 扩展密码哈希

Posted

技术标签:

【中文标题】ASP.NET Core Identity - 扩展密码哈希【英文标题】:ASP.NET Core Identity - Extending Password Hasher 【发布时间】:2016-09-16 22:25:43 【问题描述】:

我正在努力将应用程序从 Web 窗体迁移到 MVC,并选择使用 ASP.NET Core 与 MVC 6 一起使用。

在我当前的应用程序中,我有一个与 Identity 一起使用的自定义密码哈希。在我的自定义 UserManager 类中实现非常简单:

public ApplicationUserManager()
  : base(new UserStore<IdentityUser>(new AuthContext()))

    this.PasswordHasher = new SqlPasswordHasher();

我正在尝试对 .NET Core 执行相同的操作,但 UserManager 中不存在 PasswordHasher 属性。我看到构造函数将采用 IPasswordHasher 参数,所以我尝试了这个:

public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
        IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, IServiceProvider serviceProvider, ILogger<UserManager<ApplicationUser>> logger)
  : base(store, optionsAccessor, new SqlPasswordHasher(), userValidators, passwordValidators, keyNormalizer, errors,
        serviceProvider, logger)


在 SqlPasswordHasher 中,我只是重写了如下所示的 VerifyHashedPassword 方法:

public override PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)

    // My custom logic is here
    ...

但是,上述方法不起作用。我在 SqlPasswordHasher 的 VerifyHashedPassword 方法中设置了断点,它没有被触发。

我以为我做错了,我应该利用 DI 来完成这个。我更新了用户管理器的构造函数,使其不会实例化新的 SqlPasswordHasher,而是使用默认接口参数:

public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
        IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, IServiceProvider serviceProvider, ILogger<UserManager<ApplicationUser>> logger)
  : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
        serviceProvider, logger)


然后在 Startup.cs 我添加了一个作用域服务:

services.AddScoped<IPasswordHasher<ApplicationUser>, SqlPasswordHasher>();

但同样,这不起作用,并且永远不会触发 SqlPasswordHasher 中的断点。

我的自定义登录管理器有类似的一行:

services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager>();

效果很好。 ApplicationSignInManager 采用 UserManager 参数,我可以看到 UserManager 采用 IPasswordHasher 参数。

我假设 SignInManager 使用使用 PasswordHasher 的 UserManager。所以我的问题是,如何让 UserManager 使用我的自定义密码哈希?或者如果不是这样,我如何让 SignInManager 使用我的密码哈希?

编辑:我已经能够确认,当我的 ApplicationUserManager 被实例化时,我的 SqlPasswordHasher 正在构造函数中使用,因此 DI 工作正常。我只是想不通为什么我对 VerifyHashedPassword 的覆盖没有被触发。

【问题讨论】:

哪一个有效?在同一条船上。显然 v2.0 将它自己注入到用户管理器中。一直试图在 cusotm passwordvalidator 中使用它但没有成功。 @Jay 我工作过的代码。我的问题实际上与数据有关。我还没有看过 2.0 的这个,所以我不确定我上面的代码是否可以在那里工作。对不起。 (另外,抱歉这么晚才回复) 不用担心。我已经想通了。就我而言,这是一个愚蠢的错误。感谢您的留言 【参考方案1】:

事实证明,问题根本与代码无关。通过

将我的 SqlPasswordHasher 添加到服务中
services.AddScoped<IPasswordHasher<ApplicationUser>, SqlPasswordHasher>();

完美运行。

问题在于我如何迁移数据。由于我使用的是与旧版本 Identity 一起使用的现有数据库,因此我必须将以下字段添加到现有的 AspNetUsers 表中:

NormalizedUserName
ConcurrencyStamp
LockoutEnd
NormalizedEmail

但是我没有填充 NormalizedUserName 或 NormalizedEmail 字段。所以这就是为什么它从来没有触发我对 VerifyHashedPassword 的覆盖;因为它从未找到我的用户,因为它基于 NormalizedUserName 进行查找。

一旦我填充了这些字段,它就会开始触发我的 VerifyHashedPassword 方法。

【讨论】:

我只是在这上面浪费了几个小时。感谢一百万张贴您的解决方案。 @ScottHulme 没问题,我很高兴它可以提供帮助。

以上是关于ASP.NET Core Identity - 扩展密码哈希的主要内容,如果未能解决你的问题,请参考以下文章

“Identity.External”的 ASP.NET Core 标识异常

ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 14. ASP.NET Core Identity 入门

ASP.Net Core 如何在 EF Core 和 Identity 中获取用户角色

Asp.Net Core 2.1 Identity - UserStore 依赖注入

ASP.NET Core Identity 系列之四

ASP.NET Core Identity - 扩展密码哈希