【问题标题】:ASP.NET Identity Email validation token is always invalidASP.NET 身份电子邮件验证令牌始终无效
【发布时间】:2015-04-08 06:26:09
【问题描述】:

我正在尝试实现一个邀请系统,其中新创建的帐户使用UserManager.GenerateEmailConfirmationTokenUserManager.ConfirmEmail 通过电子邮件接收确认令牌。但是 ConfirmEmail 方法总是返回 false。

根据this 帖子中的建议,我实现了我的 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 的 unprotect 从未被 UserManager 的 ConfirmEmail 调用。

如果我更改 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。

感谢任何帮助!

【问题讨论】:

    标签: c# asp.net-mvc asp.net-web-api asp.net-identity owin


    【解决方案1】:

    我遇到了与您在示例 SO 帖子中提到的相同类型的问题。我已经使用它如下。在这种情况下,我使用SimpleInjector IOC 为每个网络请求注册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)
                    };
                }
            }
    

    我已添加令牌生命周期,但如果不需要,您可以将其删除。

    【讨论】:

    • 没错。 DataProtectionTokenProvider 必须是单例。其中一个加密密钥是每次创建对象时生成的 guid。
    • 示例显示正在使用默认的 IDataProtector,这不是 stackoverflow.com/questions/23455579/… 的预期目标
    【解决方案2】:

    在尝试找出 SignInManager.PasswordSignIn 方法总是失败的原因后,发现该问题是由于用户的 SecurityStamp 未在应设置的时候设置。

    希望这对其他人有所帮助。

    【讨论】:

      猜你喜欢
      • 2015-03-21
      • 2015-12-13
      • 1970-01-01
      • 2018-03-19
      • 2015-02-15
      • 2015-02-16
      • 1970-01-01
      • 2018-03-06
      • 2015-08-17
      相关资源
      最近更新 更多