生成重置密码令牌在Azure网站中不起作用

时间:2014-05-04 11:16:53

标签: asp.net asp.net-mvc azure

我正在使用ASP.NET 5附带的内置UserManager类在我的网站上实现重置密码功能。

在我的开发环境中,一切正常。但是,一旦我在作为Azure网站运行的生产站点中尝试它,我会得到以下异常:

  

System.Security.Cryptography.CryptographicException :数据保护操作失败。这可能是由于没有为当前线程的用户上下文加载用户配置文件引起的,这可能是线程模拟时的情况。

这是我设置UserManager实例的方式:

var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider(SiteConfig.SiteName);
UserManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<User>(provider.Create(ResetPasswordPurpose));

然后,我生成令牌(通过电子邮件发送给用户,以便他们确认他们确实想要重置密码):

string token = UserManager.GeneratePasswordResetToken(user.Id);

不幸的是,当它在Azure上运行时,我得到了上面的例外。

我已经用Google搜索了possible solution。但是,它根本没有用,我仍然得到同样的例外。

根据该链接,它与会话令牌有关,而不是像Azure这样的Web场。

4 个答案:

答案 0 :(得分:88)

DpapiDataProtectionProvider利用DPAPI在Web场/云环境中无法正常工作,因为加密数据只能由加密数据解密。您需要的是一种加密数据的方法,使其可以被您环境中的任何计算机解密。遗憾的是,除了DpapiDataProtectionProvider之外,ASP.NET Identity 2.0不包含任何其他IProtectionProvider实现。但是,推出自己的东西并不困难。

一种选择是如下使用the MachineKey class

public class MachineKeyProtectionProvider : IDataProtectionProvider
{
    public IDataProtector Create(params string[] purposes)
    {
        return new MachineKeyDataProtector(purposes);
    }
}

public class MachineKeyDataProtector : IDataProtector
{
    private readonly string[] _purposes;

    public MachineKeyDataProtector(string[] purposes)
    {
        _purposes = purposes;
    }

    public byte[] Protect(byte[] userData)
    {
        return MachineKey.Protect(userData, _purposes);
    }

    public byte[] Unprotect(byte[] protectedData)
    {
        return MachineKey.Unprotect(protectedData, _purposes);
    }
}

要使用此选项,您需要执行以下几个步骤。

第1步

修改代码以使用MachineKeyProtectionProvider。

using Microsoft.AspNet.Identity.Owin;
// ...

var provider = new MachineKeyProtectionProvider();
UserManager.UserTokenProvider = new DataProtectorTokenProvider<User>(
    provider.Create("ResetPasswordPurpose"));

第2步

您的Web场/云环境中的所有计算机都具有

Synchronize the MachineKey值。这听起来很可怕,但是为了让ViewState验证在Web场中正常工作(它也使用DPAPI),它与我们之前无数次执行过的步骤相同。

答案 1 :(得分:44)

考虑使用IAppBuilder.GetDataProtectionProvider()而不是声明新的DpapiDataProtectionProvider

与您类似,我通过在我找到的代码示例中配置我的UserManager来介绍此问题:

public class UserManager : UserManager<ApplicationUser>
{
    public UserManager() : base(new UserStore<ApplicationUser>(new MyDbContext()))
    {
        // this does not work on azure!!!
        var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ASP.NET IDENTITY");
        this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"))
        {
            TokenLifespan = TimeSpan.FromHours(24),
        };
    }
}

与上面链接的CodePlex问题实际上引用了blog post,该问题已使用更简单的问题解决方案进行了更新。它建议保存对IDataProtector ...

的静态引用
public partial class Startup
{
    internal static IDataProtectionProvider DataProtectionProvider { get; private set; }

    public void ConfigureAuth(IAppBuilder app)
    {
        DataProtectionProvider = app.GetDataProtectionProvider();
        // other stuff.
    }
}

...然后从UserManager

中引用它
public class UserManager : UserManager<ApplicationUser>
{
    public UserManager() : base(new UserStore<ApplicationUser>(new MyDbContext()))
    {
        var dataProtectionProvider = Startup.DataProtectionProvider;
        this.UserTokenProvider = 
                new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));

        // do other configuration
    }
}

johnso的答案也提供了一个很好的例子,说明如何使用Autofac进行连接。

答案 2 :(得分:21)

除了我在亚马逊ec2上主持外,我遇到了同样的问题 我能够通过转到IIS中的应用程序池和(在右键单击后的高级设置下)设置流程模型来解决它 - 加载用户配置文件= true。

答案 3 :(得分:12)

我遇到了同样的问题(在Azure上运行时Owin.Security.DataProtection.DpapiDataProtectionProvider失败了),Staley是正确的,你不能使用DpapiDataProtectionProvider

如果您使用的是OWIN Startup Classes,则可以避免使用自己的IDataProtectionProvider,而是使用GetDataProtectionProvider的{​​{1}}方法。

例如,使用Autofac:

IAppBuilder