我正在尝试实现一个邀请系统,在该系统中,新创建的帐户使用UserManager.GenerateEmailConfirmationToken和UserManager.ConfirmEmail通过电子邮件接收确认令牌。但是ConfirmEmail方法总是返回false。
根据这篇文章中的建议,我实现了我的MachineKeyDataProtector,并在Unity中注册如下:
container.RegisterType<IUserTokenProvider<User, Guid>,
DataProtectorTokenProvider<User, Guid>>(new InjectionConstructor(new MachineKeyDataProtector("ASP.NET Identity")));
我的UserManager注入了IUserTokenProvider,如下所示:
public UserManager(IUserStore<User, Guid> store, IUserTokenProvider<User, Guid> userTokenProvider)
: base(store)
{
// Configure validation logic for passwords
this.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
this.UserTokenProvider = userTokenProvider;
}
然后,我将GenerateEmailConfirmationToken方法封装在一个扩展方法中:
public static string GenerateUrlForEmailConfirmationToken(this UserManager<User, Guid> userManager, UrlHelper urlHelper, Guid userId)
{
var verificationCode = userManager.GenerateEmailConfirmationToken(userId);
var url = urlHelper.Link(string.Empty, new
{
controller = "Account",
action = "Verify",
userId = userId,
verificationCode = verificationCode
});
return url;
}
我正在使用它:
var url = UserManager.GenerateUrlForEmailConfirmationToken(Url, targetUser.Id);
//injects the url in a ready made html template
NotificationService.NotifyNewUser(targetUser, url);
调试GenerateUrlForEmailConfirmationToken我看到MachineKeyDataProtector的保护方法正在被调用,但是UserManager的ConfirmEmail从未调用MachineKeyDataPProtector的unprotect。
如果我更改DI配置以根据请求注册IUserTokenProvider
container.RegisterType<IUserTokenProvider<User, Guid>,
DataProtectorTokenProvider<User, Guid>>(new PerRequestLifetimeManager(),
new InjectionConstructor(new MachineKeyDataProtector("ASP.NET Identity")));
然后调用MachineKeyDataProtector的unprotect,但它会显示CryptographicException,并显示以下消息"加密操作过程中发生错误"。
这可能是验证总是错误的原因吗?如果是,如何确保调用unprotect方法?通过查看这两种情况下的对象,UserManager似乎使用了正确的IDataProtector。
感谢您的帮助!
我遇到了与您在示例SO文章中提到的问题相同的问题。我用它如下。在这种情况下,我使用SimpleInjector
IOC来注册每个web请求的Usermanager
。
我认为您只需要创建新的DataProtectorTokenProvider
,如果dataProtectionProvider
中的任何一个都不存在。此外,在UserManager
构造函数中包含DataProtectorTokenProvider创建将修复此问题。
private static void InitializeUserManager(ApplicationUserManager manager, IAppBuilder app)
{
manager.UserValidator = new UserValidator<AspNetApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
var dataProtectionProvider = app.GetDataProtectionProvider();
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<AspNetApplicationUser>(
dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = TimeSpan.FromHours(3)
};
}
}
我已经添加了令牌生命周期,但如果不需要,您可以删除它。
在试图弄清楚SignInManager.PasswordSignIn方法总是失败的原因后,发现问题是由于用户的SecurityStamp没有在本应设置的时候设置。
希望这能帮助其他人。