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 没有在应该设置的时候设置引起的。

希望这对其他人有帮助。