基於FormsAuthentication的用戶、角色身份認證(轉)
一般情況下,在我們做訪問權限管理的時候,會把用戶的正確登錄後的基本信息保存在Session中,以後用戶每次請求頁面或接口數據的時候,拿到
Session中存儲的用戶基本信息,查看比較他有沒有登錄和能否訪問當前頁面。
Session的原理,也就是在服務器端生成一個SessionID對應了存儲的用戶數據,而SessionID存儲在Cookie中,客戶端以後每次請求都會帶上這個
Cookie,服務器端根據Cookie中的SessionID找到存儲在服務器端的對應當前用戶的數據。
FormsAuthentication是微軟提供給我們開發人員使用,做身份認證使用的。通過該認證,我們可以把用戶Name 和部分用戶數據存儲在Cookie中,
通過基本的條件設置可以,很簡單的實現基本的身份角色認證。
這裏要實現的效果是:在不使用membership的情況下,使用系統提供的Authorize 實現基於角色的訪問控制。
1、創建認證信息 Ticket
在用戶登錄以後,把用戶的ID和對應的角色(多個角色用,分隔),存儲在Ticket中。
使用FormsAuthentication.Encrypt 加密票據。
把加密後的Ticket 存儲在Response Cookie中(客戶端js不需要讀取到這個Cookie,所以最好設置HttpOnly=True,防止瀏覽器攻擊竊取、偽造Cookie)。這樣下次可以從Request Cookie中讀取了。
一個簡單的Demo如下:
public ActionResult Login(string uname) { if (!string.IsNullOrEmpty(uname)) { //FormsAuthentication.SetAuthCookie(uname,true); FormsAuthenticationTicket ticket = new FormsAuthenticationTicket ( 1, uname, DateTime.Now, DateTime.Now.AddMinutes(20), true, "7,1,8", "/" ); var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,FormsAuthentication.Encrypt(ticket)); cookie.HttpOnly = true; HttpContext.Response.Cookies.Add(cookie); return RedirectToAction("UserPage"); } return RedirectToAction("Index"); }
這裏FormsAuthenticationTicket 第六個參數存儲的是string 類型的userData ,這裏就存放當前用戶的角色ID,以英文逗號分隔。
當使用用戶名 “測試” 登錄後,客戶端就會出現這樣一條記錄Cookie
2、獲取認證信息
登錄後,在內容頁,我們可以通過,當前請求的User.Identity.Name 獲取到uname信息,也可以通過讀取Request 中的Cookie 解密,獲取到Ticket,再從其中獲取uname 和 userData (也就是之前存儲的角色ID信息)。
ViewData["user"]=User.Identity.Name; var cookie = Request.Cookies[FormsAuthentication.FormsCookieName]; var ticket = FormsAuthentication.Decrypt(cookie.Value); string role = ticket.UserData; ViewData["role"] = role; return View();
3、通過註解屬性,實現權限訪問控制
在web.config中配置啟用Form認證 和 角色管理
<authentication mode="Forms"> <forms loginUrl="~/Login/Index" timeout="2880" /> </authentication> <roleManager enabled="true" defaultProvider="CustomRoleProvid"> <providers> <clear/> <add name="CustomRoleProvid" type="MvcApp.Helper.CustomRoleProvider"/> </providers> </roleManager>
當我們在Controller 、Action添加註解屬性時候,設置的Role是從哪裏得到的呢?因為沒有使用基於Membership的那一套authentication,這裏我們還要創建一個自定義的RoleProvider 。名稱為CustomRoleProvider ,繼承自 RoleProvider。這裏是在MVCApp下面的Helper文件夾中創建了自己的CustomRoleProvider.cs文件。
RoleProvider中有很多abstract 方法,我們具體只實現其中的GetRolesForUser 方法用於獲取用戶角色。這裏的用戶角色,我們可以根據拿到的用戶Id從數據庫查詢,或者拿取Session中存儲了的、或是Cookie中存儲了的。這裏我前面已經把Role存儲在Ticket的userData中了,那就從Ticket中獲取吧。
public override string[] GetRolesForUser(string username) { var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName]; var ticket = FormsAuthentication.Decrypt(cookie.Value); string role = ticket.UserData; return role.Split(‘,‘); }
在需要,驗證的Controller、Action上面添加註解屬性,比如這個Action 只允許RoleID 為包含1或2或3的訪問,而當前用戶RoleID為(7、1、8)就是用戶有權訪問了。
[Authorize(Roles="1,2,3")] public ActionResult Role() { ViewData["user"] = User.Identity.Name; return View(); }
P.S. :1、Ticket存儲在在Cookie過期時間,和關閉瀏覽器是否在記住當前票據,在FormsAuthenticationTicket實例化時候可以設置參數,
2、Role 的獲取可以不要存儲在ticket 的userData中,可以直接從數據庫讀取,userData可以存儲其他信息。
3、要想靈活配置Controller 和Action的 允許訪問的Role 可以自定義AuthorizeAttribute override裏面的OnAuthorization方法,在該方法中
讀取當前頁面允許訪問的角色ID,根據當前用戶的RoleID,進行檢查。這樣也就實現了,Role的靈活配置。
4、Ticket中的信息,最終還是存儲在cookie中,安全性方面還是自己斟酌吧,個人覺得還是把UserID和RoleID存儲在Session中的比較好。
基於FormsAuthentication的用戶、角色身份認證(轉)