2012-05-15 51 views
3

以前也有過類似的問題,但我仍然沒有答案,並且花費了相當多的時間試圖找到答案。在ASP.NET MVC中保留用戶數據

情況是這樣的。我們有一個使用Forms Authentication/LINQ到SQL數據模型的ASP.NET MVC應用程序。

每個用戶可以與1個或多個帳戶關聯。登錄後,應用程序會檢查與其關聯的帳戶數量。

=轉到錯誤頁面,讓他們知道他們有沒有訪問
=設置用戶數據使用該帳戶
2個或更多 =轉到一個頁面,允許他們選擇他們想使用的賬戶(具有在訪問期間改變的能力)

你將如何存儲這些信息?

此外,我想使用此帳戶作爲我的控制器操作的基礎。即他們訪問的後續頁面上的數據將與他們選擇的賬戶相關。

Singleton 咳嗽想到但我不確定如何實現。

這我目前正在研究的方法是一個基本的控制器,所有控制器都從將

  1. 檢查用戶是否登錄繼承。
  2. 如果是這樣,檢查他們是否有一個帳戶選擇
    • 否 - 重定向他們賬戶選擇頁面
    • 是 - 繼續執行原來的請求

這樣做的建議/最佳實踐方法是什麼?

感謝 馬爾科

+0

爲什麼不在Cookie中,即使在URL中也可以使用queryString AccountID = DGI36F2。即使使用會話,您也標記了會話狀態。 「我猜你知道這些事情是背對背的,但是你能給我們一個提出你想要這個問題的方向嗎?」 –

回答

1

不要使用基本控制器。你可以使用動作過濾器來完成這個。這將爲您提供攔截點以檢查他們是否已登錄,是否選擇了一個帳戶,甚至將他們重定向到錯誤或帳戶選擇頁面。您只需在操作過濾器的OnActionExecuting方法期間設置filterContext.Result即可阻止請求通過。在操作過程中,您可以完全訪問會話,臨時數據,Cookie和整個HttpContext,就像在控制器中一樣。你也可以使用一個過濾器屬性過濾器提供程序來注入依賴項,這樣就可以給你任何你需要的數據訪問。

至於數據建模,我不是太熟悉LINQ到SQL,但我認爲一個正常的一對多應該做的伎倆:

User (1) <-------> (0..*) Account 

public class User 
{ 
    public virtual ICollection<Account> Accounts { get; protected internal set; } 
} 

public class Account 
{ 
    public int UserId { get; protected internal set; } 
    public virtual User User { get; protected internal set; } 
} 

更新:對不起,我誤解了你的意思是「商店」。在MVC中,只有幾種方式可以存儲它 - Session,Cookie和Cache(以及TempData,這只是短期會話)是最流行的選擇。我的選擇取決於。會話可能是最簡單的,但是如果將您部署到具有負載平衡器的服務器場中,則需要考慮如果用戶會話跳轉物理機器會發生什麼情況。會議會保持不變嗎?

正如傑里米所說,還有餅乾。這裏不用擔心負載均衡,但語義比會話更難處理。例如,你必須發送一個重定向來寫入cookie,然後才能讀取它,而我從來不喜歡這樣一個事實,即你必須添加一個過期的cookie來刪除它。由於此數據是您安全性的一部分,因此您也可能需要加密cookie值。

如果使用緩存,數據最有可能仍然會生存在某個地方,例如會話(除非您使用SQL會話提供程序)。緩存可能是我最後的選擇,因爲我們使用Azure,而且它們的緩存不支持很多優秀的MVC功能。您也有與負載平衡器相同的問題,將用戶移動到集羣中的其他計算機,其中數據可能需要重新緩存。

無論哪種方式,您仍應該使用操作過濾器來代替基本Controller類。

+0

感謝您的回答@danludwig。我正在尋找一個關於如何/在哪裏存儲這些額外的用戶數據和一些代碼示例的實際實現會有所幫助。我已經將用戶和帳戶之間的一對多模型作爲我的L2S類的一部分。因此,我不確定的部分是存儲選定的帳戶,並在確保安全性的同時在後續請求中閱讀。 – Marko

+0

+1動作過濾器的良好調用。這是MVC的一個特性,我經常忽略它。 –

+0

現在我已經爲我們的Io​​C容器提供了一個很好的FilterAttributeFilterProvider,我爲各種事情使用了過濾器。使控制人員變得更加精簡,並且非常適合OP中提到的交叉問題。 – danludwig

0

你說什麼類型的秤?我們是在談論一百萬用戶還是幾千人?

我的第一個想法是創建一個字典,其中的關鍵字是登錄用戶名(假設它是唯一的)並且該值是關聯帳戶數組(關鍵或所有數據)。然後我會把字典放入緩存中。每當創建一個新的關聯時就會使用它。

這種方法存在一些問題。首先,創建新協會的速度有多快?如果他們不斷被創建,那麼緩存是一個有爭議的問題。你總是會去數據庫。其次,如果你有數百萬的用戶/協會把他們放入緩存可能不實際。

另一種可能性是會話狀態服務器,這將僅用於存儲關係。

另一種可能性是每次查詢數據庫,這取決於數據集的工作大小。當數據集增長到每次拉實時數據都不實際時,您可以構建一個適合您需求的解決方案。

至於在請求之間持續選擇的帳戶,選項可以是cookies,url或數據庫(可以是用戶的字段,即CurrentAccount,這種方法有點混亂)。

由於您使用的是MVC,因此我會使用URL以及路由和自定義路由約束,您可以創建一個包含該帳戶的URL。由於用戶必須登錄,您已經知道用戶身份。

實施例:http://www.acme.com/{account}/edit/

檢查是否一個用戶登錄可在在Global.asax動作濾波器或Application_AuthenticateRequest處理。身份驗證在ASP.NET中很好地實現。聽說很多它是由web.config中的配置值驅動的。

驗證通過後,帳戶重定向可以採用相同的方法進行。或者你可以等待並檢查一個動作過濾器。

+0

L2S是否使用動態代理?由於這些原因,我們在Session中嘗試存儲(分離)實體時遇到了問題。實際的運行時類型是通過反射創建的,並且對於運行它的機器來說是唯一的。所以如果我們在Session中存儲了一個(動態代理)實體,那麼用戶的一個請求被路由到集羣中的另一臺機器,另一臺機器不能反序列化它,因爲它具有不同的動態代理類名稱。這裏的字典解決方案是一個選項,但您可能希望在將實體數據放入基於內存的存儲器之前,將實體數據DTO添加到具體的非實體類型。 – danludwig

+0

@danludwig我從來沒有使用過L2S。我在nhibernate中遇到了與動態代理相同的問題。有時我想知道這些好處是值得頭痛的。 DTOs肯定是一種選擇。 –

+0

URL參數方法不會造成權限安全風險的巨大升級嗎?在用戶通過身份驗證後,將URL更改爲訪問用於其他用戶的數據或訪問管理權限或更高權限功能(這些權限通常不會超出其允許的權限)是微不足道的。即使在使用HTTPS時,URL也暴露給任何中間人攻擊者,因此URL標記通常也具有風險。 – pwdst