使用OWIN / Katana在Azure上的数据保护操作不成功

时间:2014-05-21 03:51:39

标签: security azure cryptography owin

我正在尝试在Azure中运行的基于OWIN / Katana的ASP.NET MVC网站上实现密码重置。

在本地运行时工作正常但在生产中失败。

我创建了一个UserToken提供程序

userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("PasswordReset"))

但是当我尝试按如下方式生成令牌时

var resetToken = await UserManager.GeneratePasswordResetTokenAsync(user.Id);

我得到以下例外。

  

System.Security.Cryptography.CryptographicException:数据   保护操作不成功。这可能是由于   没有为当前线程的用户加载用户配置文件   上下文,当线程模仿时可能就是这种情况。          在System.Security.Cryptography.ProtectedData.Protect(Byte [] userData,Byte [] optionalEntropy,DataProtectionScope scope)          在System.Security.Cryptography.DpapiDataProtector.ProviderProtect(Byte []   用户数据)          在System.Security.Cryptography.DataProtector.Protect(Byte [] userData)          在Microsoft.Owin.Security.DataProtection.DpapiDataProtector.Protect(Byte []   用户数据)          在Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider 2.d__0.MoveNext()       ---从抛出异常的先前位置开始的堆栈跟踪结束---          在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)          在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)          在Microsoft.AspNet.Identity.UserManager`2.d__e9.MoveNext()

7 个答案:

答案 0 :(得分:9)

当我尝试在Web API中使用ASP .Net标识和自定义登录功能生成令牌时,我遇到了同样的问题。

  

“数据保护操作失败了。这可能是   由于没有为当前线程加载用户配置文件而导致   用户上下文,当线程模仿时可能就是这种情况。“

我所做的只是在Microsoft Azure中创建一个名为WEBSITE_LOAD_USER_PROFILE的应用程序设置,并将其设置为1.该解决方案适用于我。

您可以看到详细信息here

答案 1 :(得分:5)

请参阅此问题的my answer。利用IAppBuilder.GetDataProtectionProvider()

可以实现更简单的解决方案

答案 2 :(得分:4)

我找到了解决方案。我不完全确定所有步骤是否都有必要,但现在我的应用程序运行正常:

1.-更新您的web.config以支持securityTokenHandlers

<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
在configSections节点中。和

    

  <securityTokenHandlers>
    <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler,
                System.IdentityModel, Version=4.0.0.0, Culture=neutral,
                PublicKeyToken=B77A5C561934E089" />

    <add
      type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler,
          System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral,
          PublicKeyToken=B77A5C561934E089">
      <sessionTokenRequirement lifetime="00:30:00"></sessionTokenRequirement>
    </add>
  </securityTokenHandlers>

</identityConfiguration>

作为常规节点。 2.-在您的Startup.Auth.cs文件中,更新您的ConfigureAuth(IAppBuilder应用程序),如下所示:

public void ConfigureAuth(IAppBuilder app)
        {

            UserManagerFactory = () =>
            {
                var userManager = new UserManager<SIAgroUser>(new UserStore<UserType>(new SIAgroUserDbContext()));

                IDataProtectionProvider provider = app.GetDataProtectionProvider();

                //userManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<UserType>(provider.Create("PasswordReset") );
                if (provider != null)
                {
                    userManager.UserTokenProvider = new DataProtectorTokenProvider<UsertType, string>(provider.Create("PasswordReset"));
                }

                return userManager;
            };

            OAuthOptions = new OAuthAuthorizationServerOptions
            {
                TokenEndpointPath = new PathString("/Token"),
                Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
                AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                AllowInsecureHttp = true
            };
            // Enable the application to use a cookie to store information for the signed in user
            // and to use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            // Enable the application to use bearer tokens to authenticate users
            app.UseOAuthBearerTokens(OAuthOptions);

            // Uncomment the following lines to enable logging in with third party login providers
            //app.UseMicrosoftAccountAuthentication(
            //    clientId: "",
            //    clientSecret: "");

            //app.UseTwitterAuthentication(
            //    consumerKey: "",
            //    consumerSecret: "");

            //app.UseFacebookAuthentication(
            //    appId: "",
            //    appSecret: "");

            //app.UseGoogleAuthentication();



        }

3.-清理Startup类的构造函数,如下所示:

static Startup()
{
   PublicClientId = "self";
}

这对我有用:)我希望它也适合你

答案 3 :(得分:2)

我把这个放在冰上一段时间但被迫回到它身上。我在这里找到了解决方案: Generating reset password token does not work in Azure Website

答案 4 :(得分:2)

我在共享主机提供商处发生此错误:

var provider = new DpapiDataProtectionProvider("SITENAME");

解决方案非常简单。首先将上面的行更改为:

var provider = new MachineKeyProtectionProvider();

然后在我的Utilities命名空间中创建一个新文件,如下所示:

using Microsoft.Owin.Security.DataProtection;
using System.Web.Security;

namespace <yournamespace>.Utilities
{
    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);
        }
    }
}

瞧瞧!问题解决了。请记住,在密码重置控制器方法中,您还必须使用此提供程序,否则您将收到Invalid Token错误。

答案 5 :(得分:2)

如果主机服务器是虚拟机,则可能正是错误消息所显示的内容。检查您的IIS中的应用程序池是否真的将Load User Profile设置为true,如异常所示:

  • 在“连接”窗格中,展开服务器名称,然后单击“应用程序池”。
  • 右键单击您的池
  • 高级设置

enter image description here

答案 6 :(得分:0)

从Owin Pipeline获取UserManager,如App_Start / Startup.Auth.cs中的设置,适用于Azure。 我不确定这是如何具体的。 DpApi应该在Azure中使用第一个链接中描述的解决方案。

如果DpApi在Web.config中设置了静态机器密钥,则所有服务器机器都能够解密由webfarm中另一台机器创建的加密数据。

(标准模板中给出的代码 - 来自AccountController.cs)

 private UserManager userManager;
    public UserManager UserManager
    {
        get { return userManager ?? HttpContext.GetOwinContext().GetUserManager<UserManager>(); }
        private set { userManager = value; }
    }