ASP.NET 身份电子邮件验证令牌始终无效
ASP.NET Identity Email validation token is always invalid
我正在尝试实施一个邀请系统,新创建的帐户使用 UserManager.GenerateEmailConfirmationToken and UserManager.ConfirmEmail 通过电子邮件收到确认令牌。但是 ConfirmEmail 方法总是返回 false。
根据 this post 中的建议,我实现了我的 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 的保护方法,但是 MachineKeyDataProtector 的取消保护从未被 UserManager 的 ConfirmEmail 调用。
如果我更改 DI 配置以根据请求注册 IUserTokenProvider
container.RegisterType<IUserTokenProvider<User, Guid>,
DataProtectorTokenProvider<User, Guid>>(new PerRequestLifetimeManager(),
new InjectionConstructor(new MachineKeyDataProtector("ASP.NET Identity")));
然后调用 MachineKeyDataProtector 的取消保护,但它抛出带有以下消息的 CryptographicException "Error occurred during a cryptographic operation."。
这可能是验证总是错误的原因吗?如果是这样,如何确保调用 unprotect 方法?通过查看两种情况下的对象,UserManager 似乎使用了正确的 IDataProtector。
感谢任何帮助!
我遇到了与您在示例中提到的相同类型的问题 SO post。我已经使用它如下。在这种情况下,我使用 SimpleInjector
IOC 为每个 Web 请求注册 Usermanager
。
我认为如果 dataProtectionProvider
中的任何一个不存在,您只需要创建新的 DataProtectorTokenProvider
。此外,在 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 没有在应该设置的时候设置引起的。
希望这对其他人有帮助。
我正在尝试实施一个邀请系统,新创建的帐户使用 UserManager.GenerateEmailConfirmationToken and UserManager.ConfirmEmail 通过电子邮件收到确认令牌。但是 ConfirmEmail 方法总是返回 false。
根据 this post 中的建议,我实现了我的 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 的保护方法,但是 MachineKeyDataProtector 的取消保护从未被 UserManager 的 ConfirmEmail 调用。
如果我更改 DI 配置以根据请求注册 IUserTokenProvider
container.RegisterType<IUserTokenProvider<User, Guid>,
DataProtectorTokenProvider<User, Guid>>(new PerRequestLifetimeManager(),
new InjectionConstructor(new MachineKeyDataProtector("ASP.NET Identity")));
然后调用 MachineKeyDataProtector 的取消保护,但它抛出带有以下消息的 CryptographicException "Error occurred during a cryptographic operation."。
这可能是验证总是错误的原因吗?如果是这样,如何确保调用 unprotect 方法?通过查看两种情况下的对象,UserManager 似乎使用了正确的 IDataProtector。
感谢任何帮助!
我遇到了与您在示例中提到的相同类型的问题 SO post。我已经使用它如下。在这种情况下,我使用 SimpleInjector
IOC 为每个 Web 请求注册 Usermanager
。
我认为如果 dataProtectionProvider
中的任何一个不存在,您只需要创建新的 DataProtectorTokenProvider
。此外,在 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 没有在应该设置的时候设置引起的。
希望这对其他人有帮助。