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

And*_*rew 58 asp.net asp.net-mvc azure

我正在使用UserManagerASP.NET 5附带的内置类在我的站点上实现重置密码功能.

在我的开发环境中一切正常.但是,一旦我在作为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));
Run Code Online (Sandbox Code Playgroud)

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

string token = UserManager.GeneratePasswordResetToken(user.Id);
Run Code Online (Sandbox Code Playgroud)

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

我用Google搜索并发现了这种可能的解决方案.但是,它根本不起作用,我仍然得到同样的例外.

根据该链接,它与会话令牌有关,这些会话令牌不在像Azure这样的Web场上工作.

Chr*_*ley 88

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

一种选择是使用MachineKey类,如下所示:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用此选项,您需要执行几个步骤.

步骤1

修改您的代码以使用MachineKeyProtectionProvider.

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

var provider = new MachineKeyProtectionProvider();
UserManager.UserTokenProvider = new DataProtectorTokenProvider<User>(
    provider.Create("ResetPasswordPurpose"));
Run Code Online (Sandbox Code Playgroud)

第2步

在Web场/云环境中的所有计算机上同步MachineKey值.这听起来很可怕,但是为了让ViewState验证在Web场中正常工作(它也使用DPAPI),我们之前无数次执行过相同的步骤.


Lor*_*sen 46

考虑使用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),
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

与上面链接的CodePlex问题实际上引用了一个博客文章,该帖子已经使用更简单的问题解决方案进行了更新.它建议保存一个静态引用IDataProtector...

public partial class Startup
{
    internal static IDataProtectionProvider DataProtectionProvider { get; private set; }

    public void ConfigureAuth(IAppBuilder app)
    {
        DataProtectionProvider = app.GetDataProtectionProvider();
        // other stuff.
    }
}
Run Code Online (Sandbox Code Playgroud)

...然后从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
    }
}
Run Code Online (Sandbox Code Playgroud)

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


boo*_*one 23

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


Aar*_*n B 12

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

如果您正在使用OWIN Startup Classes,则可以避免IDataProtectionProvider使用自己的GetDataProtectionProvider方法,而是使用方法IAppBuilder.

例如,使用Autofac:

internal static IDataProtectionProvider DataProtectionProvider;    

public void ConfigureAuth(IAppBuilder app)
{
    // ...

    DataProtectionProvider = app.GetDataProtectionProvider();

    builder.Register<IDataProtectionProvider>(c => DataProtectionProvider)
        .InstancePerLifetimeScope();

    // ...
}
Run Code Online (Sandbox Code Playgroud)