2012-11-01 46 views
4

我正在調用一個服務,並且我需要傳遞用戶的永久安全令牌,並提供每一個請求。MVC在會話中保存一個令牌

爲了做到這一點,我添加了這個方法我的基本控制器類:

protected UserData getUsr() 
{ 
     try 
     { 
      UserData usr = new UserData(); 
      usr.SecurityToken = Session["secToken"].ToString(); 

      MembershipUser mvcUser = Membership.GetUser(HttpContext.User.Identity.Name); 
      usr.Id = (int)mvcUser.ProviderUserKey; 

      return usr; 
     } 
     catch (Exception ex) 
     { 
      log.Debug("Could not create usr object", ex); 
      throw new Exception("Could not authenticate"); 
     } 
    } 

這裏這個問題,有時User.Identity數據出持續的會話數據,從而導致莫名其妙的錯誤發生在用戶看到他們已經登錄但隨後他們的請求失敗的情況下發生。

有沒有更好的方式來存儲這個令牌/我可以存儲它的方式,它會過期每當User.Identity對象過期?另外,如果有人知道對HttpContext和MVC的一些很好的基本理解示例/文檔,授權過濾器將會很棒。

+0

您可以簡單地檢查其中一個值,令牌或User.Identity數據是否無效。然後用戶需要再次登錄 – middelpat

+0

是的,但是這需要在MVC檢查授權過濾器的任何地方發生,否則他們可以進入頁面,並花費10分鐘時間填寫表單,以便僅因爲令牌過期而拒絕。 –

+0

我看了一些其他的問題,並重寫MVC onauthorize方法是非常有效的。它並沒有完全解決這個問題,所以我要去尋找onauthenticate方法(不管是什麼),看看我是否可以重寫它。 –

回答

5

我會去在表單身份驗證cookie本身存儲用戶的安全令牌。 FormsAuthenticationTicket類包含一個UserData屬性,您可以在其中包含附加信息。

UserData屬性中指定的值被包括作爲 認證券的cookie一部分,像其他票領域,是 加密,並基於該表格認證系統的配置 驗證。

這是一個article,它描述瞭如何將附加信息存儲到表單身份驗證cookie。

This是一篇很大的文章,它解釋了將更多數據存儲到窗體身份驗證中的情況。 cookie以及如何閱讀它。代碼是用VB編寫的,格式不正確。您必須向下滾動至步驟4:在票證中存儲其他用戶數據。

這個thread會給你一個快速的答案,你可以從cookie中讀取UserData

我會去創建一個自定義ValueProvider,如here所述,它將從認證中讀取安全令牌。 cookie和動作參數提要。

+0

我喜歡這個解決方案,因爲它很容易,它確保了兩個數據總是同時在那裏。 –

1

您可以將用戶安全令牌,IP地址和時間戳放在字符串中。使用對稱算法(如AES)對字符串進行加密,並將其作爲cookie進行放置。然後更改您的代碼以從Cookie中讀取。您可以驗證cookie中的ip地址與用戶ip地址匹配,這將防止有人竊取cookie值並重播它。 Here是關於AES的MSDN文檔(Rjindael是原始名稱)。在這種方案中,令牌不會過期,直到cookie過期和/或達到超時。我強烈建議你設置一個超時時間,而不是永久或持久化,這會使得該方案不太安全以排除超時。由於這些算法的CBC模式,也會將時間戳放在cookie值的開始位置,這會影響加密字符串因開始時的位數變化(雪崩效應)而出現的方式。

ASP.NET成員資格提供程序還具有身份驗證Cookie,因此此Cookie不應在成員身份Cookie之前過期。會話必須在超時時過期,因爲不能保證用戶仍然在那裏,因爲HTTP是無狀態的,而cookie是在用戶的控制下並且每一次發出請求都會被傳遞。

getUsr功能

protected UserData getUsr() 
{ 
    try 
    { 
     UserData usr = new UserData(); 

     string token = Request.Cookies["secToken"].Value; 

     // implement RijndaelManaged encryption/decryption scheme 
     // this can also be serialized as an object to make cleaner 
     var tokenValues = Decrypt(token).Split(','); 

     // The timeout expired 
     if (DateTime.Now > DateTime.Parse(tokenValues[1])) 
     { 
      throw new Exception("Timeout"); 
     } 

     // someone stole this cookie or is on a different internet connection 
     if (tokenValues[0] != System.Web.HttpContext.Current.Request.UserHostAddress) 
     { 
      throw new Exception("Invalid IP"); 
     } 

     // You're ok everything checks out 
     usr.SecurityToken = tokenValues[3].ToString(); 

     MembershipUser mvcUser = Membership.GetUser(HttpContext.Current.User.Identity.Name); 
     usr.Id = (int)mvcUser.ProviderUserKey; 

     return usr; 
    } 
    catch (Exception ex) 
    { 
     log.Debug("Could not create usr object", ex); 
     throw new Exception("Could not authenticate"); 
    } 
} 
+0

我很擔心這種方法的安全性。將這種信息存儲在cookie中是否是行業標準?另外,更重要的是,我該如何處理超時?每次用戶點擊頁面時,ASP.net會員cookie都會將超時重置爲30分鐘,這意味着我每次都需要重寫我的身份驗證cookie。我需要覆蓋某些ASP.NET方法的默認行爲嗎? –

+0

有一個問題可能是用戶來自的IP地址可能是共享IP,因此同一網絡上的用戶可能會劫持cookie。至於數據的安全性受到損害,我認爲cookie可能基於算法(AES)本身進行解密的可能性很小,這取決於您的密鑰生成,存儲密鑰的位置和方式。會話也可能被劫持,因爲會話ID是作爲cookie發送的,中間人可以竊取並重播它並執行相同的操作。 http://codebutler.com/firesheep/展示瞭如何做到這一點。 – nerdybeardo

+0

至於超時時間,您只需要在cookie值中加入日期時間標記作爲加密的一部分,每次cookie被驗證並重新寫入cookie時,您可以將其重置爲30分鐘,雖然這可能有點矯枉過正所以也許只有在短時間內才能做到這一點,例如將其設置爲30分鐘,如果只剩下5分鐘,則重新創建並重寫Cookie。這樣你就不會爲每個請求寫入cookie。 – nerdybeardo

1

也許我說的話是很愚蠢的,但在過去我也有類似的問題,我通過簡單的設置會話到期時間比該記錄更解決了它到期時間。 Whenerver,你可以用刷新會話數據的安全令牌進入網站b,因此確保它們將持續用戶登錄的整個時間。 會話持續時間更長的事實不會導致問題,因爲只有登錄用戶可以使用該數據,並且新用戶登錄舊會話條目時被替換。

+0

如果他們關閉瀏覽器會怎麼樣?這將刪除他們的會話;它是否也會刪除他們的驗證cookies? –

+0

會話和身份驗證均由Cookie處理,因此只需將相同的設置應用於他們即可,唯一的例外是會話過期時間長於登錄時間。如果兩個cookie都設置爲不持久(會話cookie)...是的。但會話將繼續浪費服務器上的資源,直到會話到期,然後清除數據結構。 –

0

如果User.Identiy超過會話,爲什麼不將該令牌作爲索賠存儲在身份中?例如:

  var claims = new[] 
      { 
       new Claim("access_token", string.Format("Bearer {0}", token)), 
      }; 

      var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie); 

      Request.GetOwinContext().Authentication.SignIn(options, identity);