2014-05-21 25 views
12

我試圖在Azure中運行的基於OWIN/Katana的ASP.NET MVC網站上實現密碼重置。使用OWIN/Katana在Azure上的數據保護操作失敗

它在本地運行時工作正常,但在生產中失敗。

我創建了一個UserToken提供商

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

但是,當我試圖生成令牌如下我會在年底異常顯示。

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

System.Security.Cryptography.CryptographicException: The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating. 
    at System.Security.Cryptography.ProtectedData.Protect(Byte[] userData, Byte[] optionalEntropy, DataProtectionScope scope) 
    at System.Security.Cryptography.DpapiDataProtector.ProviderProtect(Byte[] userData) 
    at System.Security.Cryptography.DataProtector.Protect(Byte[] userData) 
    at Microsoft.Owin.Security.DataProtection.DpapiDataProtector.Protect(Byte[] userData) 
    at Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider`2.<GenerateAsync>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at Microsoft.AspNet.Identity.UserManager`2.<GenerateUserTokenAsync>d__e9.MoveNext() 
+0

您是否找到了解決方案? – Dragouf

+0

請注意。有任何想法嗎? –

+0

是的,我找到了解決方法,但我並不完全滿意。看起來這是由於應用程序中的AppName參數不同。所以我使用OwinStartupAttribute的配置(IAppBuilder應用程序)調用的應用參數來實例化IDataPRovider,它似乎工作。要獲取數據提供者對象,可以這樣做:app.GetDataProtectionProvider()。告訴我它是否可以工作 – Dragouf

回答

3

我找到了解決方案。我不完全相信,如果所有必要的步驟,它的工作,但現在我的應用程序完美的作品:

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.-清理您的啓動類的構造函數是這樣的:

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

爲我工作:)我希望它爲你工作太

+0

我認爲這部分很重要:IDataProtectionProvider provider = app.GetDataProtectionProvider();就像我在之前的評論中所說的,我認爲這是AppName的問題。如果您通過自己實例化數據保護提供程序,您將設置與它使用的應用程序名稱不同的名稱... – Dragouf

+0

我認爲如果您不使用任何IOS:應用程序,則使用Owin上下文來實例化用戶管理器會更好。 CreatePerOwinContext(ExtranetDbContext.Create); app.CreatePerOwinContext (ApplicationUserManager.Create); – Dragouf

0

從Owin管道獲取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; } 
    } 
2

請看看我的my answer這個問題。一個更簡單的解決方案可以利用IAppBuilder.GetDataProtectionProvider()

1

發生此錯誤,我在一個共享的託管服務提供商,在該行實現:

var provider = new DpapiDataProtectionProvider("SITENAME"); 

的解決方案是非常簡單的。首先,上述行改成這樣:

var provider = new MachineKeyProtectionProvider(); 

然後創建一個新的文件,我在我的公用事業的命名空間,就像這樣:

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); 
     } 
    } 
} 

的Et瞧!問題解決了。請記住,在您的密碼重置控制器方法中,您還必須使用此提供程序,否則您將收到Invalid Token錯誤。

4

當我嘗試在Web API中使用ASP .Net身份和自定義登錄功能生成令牌時,我遇到了同樣的問題。

"The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating." 

我所做的只是簡單地創建微軟Azure稱爲WEBSITE_LOAD_USER_PROFILE應用程序設置,並將其設置爲1。該解決方案是我的作品。

您可以查看詳細信息here

+0

這裏最簡單的解決方案,就像鏈接所說的那樣,我需要避免使用此設置的BASIC和SHARED計劃。 – ericosg