2014-05-13 11 views
14

我將自定義聲明(例如用戶的真實姓名)存儲在ASP.NET身份Cookie中,以避免對每個請求進行不必要的數據庫查詢。至少這是我認爲這個代碼是這樣做的:身份Cookie在一段時間後失去定製聲明信息

var identity = await user.GenerateUserIdentityAsync(UserManager); 
identity.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName))); 
// etc. 
AuthenticationManager.SignIn(new AuthenticationProperties {IsPersistent=true}, identity); 

這工作得很好,我可以檢索與這些說法:

private static string GetClaim(string claimType) 
{ 
    var identity = (ClaimsPrincipal) Thread.CurrentPrincipal; 
    var claim = identity.Claims.SingleOrDefault(o => o.Type == claimType); 
    return claim == null ? null : claim.Value; 
} 

identity.Claims屬性包含下面的權利要求,符合市場預期:

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: ced2d16c-cb6c-4af0-ad5a-09df14dc8207 
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: [email protected] 
http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity 
AspNet.Identity.SecurityStamp: 284c648c-9cc7-4321-b0ce-8a347cd5bcbf 
http://schemas.microsoft.com/ws/2008/06/identity/claims/role: Admin 
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: My Name 

麻煩的是,經過一段時間(通常幾個小時)後,我的自定義聲明似乎消失了 - 在此示例中,givenname不再存在於枚舉中離子。用戶仍然通過身份驗證,所有默認聲明仍然存在。

這是怎麼回事,我該如何解決這個問題?我能想到的唯一事情就是cookie過期並在幕後重新發布,但我不知道爲什麼(或如果)會發生。

+0

Hi @James。我能問個問題嗎。你說你這樣做是爲了「避免每次請求中的不必要的數據庫查詢」。這使我認爲Identity必須在每個請求上訪問數據庫。真的嗎?我做了一個非常簡單的測試,它似乎沒有訪問數據庫(基於沒有'DbContext.Database.Log'的輸出),但也許它被緩存了。很高興知道每個HTTP請求數據庫訪問將是一個壞消息。 –

+0

@JonSmith如果我沒有緩存用戶的真實姓名(即在auth cookie中),每當我想知道他們的名字是什麼時,我都需要查詢Customers表。 – James

+0

嗨@詹姆斯。好的,我現在明白了。我有幾乎相同的問題,但通過將它作爲聲明添加到數據庫中,它自動出現在cookie中。我假設cookie必須攜帶所有用戶的信息,這就是它如何設置IPrincipal而不需要查找。 –

回答

16

是的,問題很可能是cookie過期。由於您沒有將自定義聲明添加到數據庫中的用戶聲明中,所以它們在刷新時會丟失,因爲您沒有在要調用的方法內添加聲明。您可以通過添加要求:

userManager.AddClaim(user.Id, new Claim(ClaimTypes.GivenName, user.FirstName)); 

,或者你可以(在默認情況下其user.GenerateUserIdentityAsync)移動這個當cookie被再生時調用的方法內。

 app.UseCookieAuthentication(new CookieAuthenticationOptions { 
      AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
      LoginPath = new PathString("/Account/Login"), 
      Provider = new CookieAuthenticationProvider { 
       // Enables the application to validate the security stamp when the user logs in. 
       // This is a security feature which is used when you change a password or add an external login to your account. 
       OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
        validateInterval: TimeSpan.FromMinutes(30), 
        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 
      } 
     }); 
+1

非常感謝您的建議。我寧願不堅持對數據庫的聲明,因爲那麼用戶的名字將被存儲兩次(在用戶和聲明表中),我需要擔心保持兩者都是最新的。請你能詳細說明'GenerateUserIdentityAsync'方法嗎?我在哪裏需要包含您提供的片段,以及我在哪裏添加'GivenName'聲明?再次感謝。 – James

+3

您已經有一個GenerateUserIdentity方法,它在您的登錄時被調用。您應該將代碼添加到該方法中,並且您應該很好 –

+0

我有類似的要求,但我的用戶名(以及其他應用程序信息)實際上存儲在一個單獨的數據庫(不是身份數據庫)中,所以在登錄時,當調用GenerateUserIdentityAsync()方法時,我需要查詢我的其他EF dbcontext來檢索該數據,並將自定義聲明添加到標識中,正確? –

相關問題