2013-12-18 16 views
6

我正在實施一個應用程序,其中使用該應用程序的公司中的每臺機器都有一名技工。我試圖實現用戶策略,如果用戶身處「機械師」角色 - 用戶名爲Machine1,並且已登錄該機器,則只有一個用戶可以同時使用Machine1用戶名登錄公司。 如果其他人試圖用相同的用戶名登錄,應該阻止並通知已登錄的用戶。當會話超時到期時,我應該註銷登錄的用戶並釋放要使用的登錄名。當用戶自己註銷時也會發生同樣的情況。我試圖在asp.net MVC 4應用程序上構建它。如何使MVC 4應用程序中的單個用戶登錄

我想過在數據庫中使用SessionId,UserId和IsLoggedIn布爾值。但在這種情況下,我需要在MVC應用程序的會話超時中更改登錄標誌以寫入數據庫,如果許多用戶登錄,這看起來有點矯枉過正。

實現會是什麼樣子?我應該使用哪些方法或屬性來處理數據庫中的會話管理?

FYI

我已經作出了自己的方法,在這裏我檢查,如果用戶登錄,那就是:

public static bool ValidateUser(string username, string password, string companyName) 
{ 
    int? companyId = myRepository.GetCompanyId(companyName); 

    int? userId = companyId == 0 ? null : myRepository.GetUserId(username, companyId); 

    if (userId.HasValue && userId.Value != 0) 
    { 
     var userKey = Security.GenerateUserKey(username, companyName); 
     return WebSecurity.Login(userKey, password); 
    } 
    else 
    { 
     return false; 
    } 
} 

在這裏,在這個方法我能以某種方式檢查會話ID是與數據庫中相同。

+1

我看到提到兩個用戶都在用戶組中名稱「Mechanic」和以相同帳戶名稱登錄的用戶。你將哪一個基於你的單人政策?另外,我想知道只能由一個人同時使用的Web應用程序的好處是什麼。 – Flater

+0

我編輯了問題 – dlght

+1

_「但在這種情況下,我需要在MVC應用程序中更改會話超時中的登錄標誌以寫入數據庫,如果許多用戶登錄,這看起來過度。」_ - 你是什麼意味着「矯枉過正」?當用戶忘記或忘記用戶時,是否要註銷用戶?它不起作用嗎?你擔心它不會有效嗎?只要嘗試像這樣實現它,請參閱[如何獲得會話結束的通知?](http://stackoverflow.com/questions/1413407/),並在遇到實際問題時返回。 – CodeCaster

回答

3

我做了類似的事情,他們總是參與其中。你需要某種鎖或信號量。 這是最好的數據庫方面做回購行動。

我不確定這應該算作一個實際的答案,因爲我沒有給你一個實現如此多的方法。

方法1:

一旦通過認證,使用戶行鎖定獨佔鎖。一旦你的用戶註銷,回收(EF)連接被回收,獨佔鎖被釋放。

您需要在登錄過程中使用try-catch(可能會使用超時),因爲這將是登錄嘗試的結果。

方法2:

登錄後,通過帶走登錄權限鎖定用戶:

MembershipUser muUser = Membership.GetUser(strUsernameToActOn); 
muUser.IsApproved = false; 
Membership.UpdateUser(muUser); 

注:這種方法需要在確保用戶被解鎖維護註銷後。這可能會很棘手。您可以選擇使用destructor操作或後臺守護程序,該後臺守護程序檢查此用戶上次實際處於活動狀態。

方法3:

有一個時間戳中登錄您的用戶記錄。每次用戶點擊數據庫以執行任何操作時更新此時間戳。

在登錄過程中,檢查時間戳和合理的偏移來觀看在允許的日誌記錄。

在註銷,空白的時間戳。

方法4

使用singleton類:在登錄時,創建構造函數添加用戶的ID(或名稱)用戶不允許登錄的靜態列表的實例。

使用destructor行動來移除用戶(或者通過存在單例實例)。

不允許任何用戶登錄爲靜態 - 單身人士驅動列表的一部分。

+0

謝謝你的答案戴夫。我採取了我最初的方法:數據庫中的一個表,其中包含UserId和SessionId字段。在用戶登錄時,我檢查用戶是否已經登錄,如果他是,sessionId是否與數據庫中的sessionId匹配。在註銷/會話過期時,我從數據庫中刪除具有sessionId的匹配當前值的用戶。 – dlght

+0

這是我的Session_End中()函數: 保護無效Session_End中(對象發件人,EventArgs的) { 使用(VAR的DataContext =新MyRepository(新ProjectEntities())) { 串的sessionID = Session.SessionID; (sessionID!= null) if(sessionID!= null) { dataContext.DeleteUser(sessionID); dataContext.Save(); } } } – dlght

3

這個問題的癥結在於知道用戶何時註銷以允許下一個用戶使用相同的名稱。我不知道在Web應用程序中執行此操作的確切方法,但這裏有一種方法可以通過控制登錄持續的時間來近似瞭解用戶註銷的時間。爲了進行測試,我將超時設置爲1分鐘,這樣我就可以快速測試具有相同用戶名的不同用戶。你可以通過web.config來控制它。

<forms loginUrl="~/Account/Login" timeout="1" slidingExpiration="false" /> 

請注意,我將slidingExpiration設置爲false以準確知道它們何時會被註銷。如果使用滑動過期,則無法預測何時發生註銷,因爲您無法指望用戶實際註銷。

爲了跟蹤當前登錄的用戶,我使用了一個MemoryCache並使用其過期策略自動跟蹤我的時間。這是我寫的一個簡單的助手類來管理這個。

public class UserManager 
{ 
    public static bool IsLoggedIn(string username) 
    { 
     ObjectCache cache = MemoryCache.Default; 
     return !string.IsNullOrEmpty(cache[username] as string); 

    } 

    public static void SetToLoggedIn(string username) 
    { 
     ObjectCache cache = MemoryCache.Default; 
     CacheItemPolicy policy = new CacheItemPolicy(); 
     //Expires after 1 minute. 
     policy.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddMinutes(1)); 
     cache.Set(username, username, policy); 

    } 
} 

請注意,我使用AbsoluteExpiration並將超時設置爲我爲表單身份驗證設置的相同長度。這會在寫入對象的1分鐘內從緩存中清除對象。這樣我可以檢查緩存中是否存在對象,以確定用戶登錄的分配時間是否已過。我使用用戶名作爲緩存對象的關鍵字,因爲我們在任何時候都檢查具有該用戶名的一個用戶在系統中。

現在我們只需更改我們的登錄操作即可。

[HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public ActionResult Login(LoginModel model, string returnUrl) 
    { 
     if (ModelState.IsValid) 
     { 
      if (UserManager.IsLoggedIn(model.UserName)) 
      { 
       ModelState.AddModelError("", "A user with that user name is already logged in."); 
       return View(model); 
      } 
      if (WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe)) 
      { 
       UserManager.SetToLoggedIn(model.UserName); 
       return RedirectToLocal(returnUrl); 
      } 
     } 

     // If we got this far, something failed, redisplay form 
     ModelState.AddModelError("", "The user name or password provided is incorrect."); 
     return View(model); 
    } 

我使用SimpleMembership在MVC 4應用程序上測試了它,它工作正常。這種方法唯一的缺點是你需要一個絕對超時而不是滑動。獲取超時的正確設置對於減少用戶在特定時間間隔註銷時的失敗以及將其他用戶不得不等待登錄的時間減到最小至關重要。

+0

因此,如果用戶在一分鐘後仍然登錄,緩存項目將被刪除並登錄返回空?我錯過了什麼? –

+0

IsLoggedIn返回一個布爾值。它使用string.IsNullOrEmpty檢查緩存對象是否存在,因爲存儲在緩存中的對象只是一個字符串。如果緩存的對象不存在,則該用戶的分配時間(在緩存策略中設置)已過期,否則該時間未到期。在緩存中設置的分配時間與用戶可以登錄的時間相同,正如web.config中爲表單身份驗證所設置的那樣。 –

+0

在我的情況下,使用內存緩存不是一個選項。我與所有記錄的用戶一起使用SQL表,並在登錄和Session_End()上添加刪除。 – dlght

相關問題