1. 程式人生 > >基於FormsAuthentication的用戶、角色身份認證(轉)

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

就會 攻擊 context public contex onf decrypt 數據 分用

一般情況下,在我們做訪問權限管理的時候,會把用戶的正確登錄後的基本信息保存在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的用戶、角色身份認證(轉)