基於FormsAuthentication的用戶、角色身份認證

基於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中的比較好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章