ASP.NET核心标识-扩展密码哈希器



我正在努力将应用程序从Web Forms转移到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使用UserManager,后者使用PasswordHasher。所以我的问题是,如何让UserManager使用我的自定义密码哈希器?或者,如果不是这样,我该如何让SignInManager使用我的密码哈希器?

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

事实证明,问题根本与代码无关。通过将我的SqlPasswordHasher添加到服务中

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

工作非常完美。

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

NormalizedUserName
ConcurrencyStamp
LockoutEnd
NormalizedEmail

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

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

最新更新