【MVC】ASP.NET MVC Forms驗證機制

ASP.NET MVC 3數據庫

  使用Forms身份驗證cookie

身份驗證流程ide

1、用戶登陸函數

  一、驗證表單:ModelState.IsValidui

  二、驗證用戶名和密碼:經過查詢數據庫驗證加密

  三、若是用戶名和密碼正確,則在客戶端保存Cookie以保存用戶登陸狀態:SetAuthCookiespa

    1):從數據庫中查出用戶名和一些必要的信息,並把額外信息保存到UserData中code

    2):把用戶名和UserData保存到 FormsAuthenticationTicket 票據中orm

    3):對票據進行加密 Encrypt對象

    4):將加密後的票據保存到Cookie發送到客戶端

  四、跳轉到登陸前的頁面

2、驗證登陸

  一、在Global中註冊PostAuthenticateRequest事件函數,用於解析客戶端發過來的Cookie數據

    1):經過 HttpContext.Current.User.Identity 判斷用戶是否登陸(FormsIdentity,IsAuthenticated,AuthenticationType)

    2):從HttpContext 的Request的Cookie中解析出Value,解密獲得 FormsAuthenticationTicket  獲得UserData

  二、角色驗證

    在Action加入 Authorize特性,能夠進行角色驗證

      在 HttpContext.Current.User 的 IsInRole 方法進行角色認證(須要重寫)

 

 

下面是代碼,以上用到的全部驗證的類都進行重載

1、首先是用戶用戶身份認證的 IPrincipal

  這裏抽象出通用屬性,定義兩個 IPrincipal

    //通用的用戶實體
    public class MyFormsPrincipal<TUserData> : IPrincipal
        where TUserData : class, new()
    {
        //當前用戶實例
        public IIdentity Identity { get; private set; }
        //用戶數據
        public TUserData UserData { get; private set; }


        public MyFormsPrincipal(FormsAuthenticationTicket ticket, TUserData userData)
        {
            if (ticket == null)
                throw new ArgumentNullException("ticket");
            if (userData == null)
                throw new ArgumentNullException("userData");

            Identity = new FormsIdentity(ticket);
            UserData = userData;
        }

        //角色驗證
        public bool IsInRole(string role)
        {
            var userData = UserData as MyUserDataPrincipal;
            if (userData == null)
                throw new NotImplementedException();

            return userData.IsInRole(role);
        }

        //用戶名驗證
        public bool IsInUser(string user)
        {
            var userData = UserData as MyUserDataPrincipal;
            if (userData == null)
                throw new NotImplementedException();

            return userData.IsInUser(user);
        }
    }

  通用實體裏面能夠存放數據實體,而且把角色驗證和用戶驗證放到了具體的數據實體裏面

    //存放數據的用戶實體
    public class MyUserDataPrincipal : IPrincipal
    {
        //數據源
        private readonly MingshiEntities mingshiDb = new MingshiEntities();

        public int UserId { get; set; }
        
        //這裏能夠定義其餘一些屬性
        public List<int> RoleId { get; set; }

        //當使用Authorize特性時,會調用改方法驗證角色 
        public bool IsInRole(string role)
        {
            //找出用戶全部所屬角色
            var userroles = mingshiDb.UserRole.Where(u => u.UserId == UserId).Select(u => u.Role.RoleName).ToList();

            var roles = role.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
            return (from s in roles from userrole in userroles where s.Equals(userrole) select s).Any();
        }

        //驗證用戶信息
        public bool IsInUser(string user)
        {
            //找出用戶全部所屬角色
            var users = user.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            return mingshiDb.User.Any(u => users.Contains(u.UserName));
        }

        
        [ScriptIgnore]    //在序列化的時候忽略該屬性
        public IIdentity Identity { get { throw new NotImplementedException(); } }
    }

2、用於驗證和設置Cookie的 FormsAuthentication

    //身份驗證類
    public class MyFormsAuthentication<TUserData> where TUserData : class, new()
    {
        //Cookie保存是時間
        private const int CookieSaveDays = 14;

        //用戶登陸成功時設置Cookie
        public static void SetAuthCookie(string username, TUserData userData, bool rememberMe)
        {
            if (userData == null)
                throw new ArgumentNullException("userData");

            var data = (new JavaScriptSerializer()).Serialize(userData);

            //建立ticket
            var ticket = new FormsAuthenticationTicket(
                2, username, DateTime.Now, DateTime.Now.AddDays(CookieSaveDays), rememberMe, data);

            //加密ticket
            var cookieValue = FormsAuthentication.Encrypt(ticket);

            //建立Cookie
            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue)
            {
                HttpOnly = true,
                Secure = FormsAuthentication.RequireSSL,
                Domain = FormsAuthentication.CookieDomain,
                Path = FormsAuthentication.FormsCookiePath,
            };
            if (rememberMe)
                cookie.Expires = DateTime.Now.AddDays(CookieSaveDays);

            //寫入Cookie
            HttpContext.Current.Response.Cookies.Remove(cookie.Name);
            HttpContext.Current.Response.Cookies.Add(cookie);
        }

        //從Request中解析出Ticket,UserData
        public static MyFormsPrincipal<TUserData> TryParsePrincipal(HttpRequest request)
        {
            if (request == null)
                throw new ArgumentNullException("request");

            // 1. 讀登陸Cookie
            var cookie = request.Cookies[FormsAuthentication.FormsCookieName];
            if (cookie == null || string.IsNullOrEmpty(cookie.Value)) return null;

            try
            {
                // 2. 解密Cookie值,獲取FormsAuthenticationTicket對象
                var ticket = FormsAuthentication.Decrypt(cookie.Value);
                if (ticket != null && !string.IsNullOrEmpty(ticket.UserData))
                {
                    var userData = (new JavaScriptSerializer()).Deserialize<TUserData>(ticket.UserData);
                    if (userData != null)
                    {
                        return new MyFormsPrincipal<TUserData>(ticket, userData);
                    }
                }
                return null;
            }
            catch
            {
                /* 有異常也不要拋出,防止攻擊者試探。 */
                return null;
            }
        }
    }

3、用於驗證角色和用戶名的Authorize特性

    //驗證角色和用戶名的類
    public class MyAuthorizeAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
        {
            var user = httpContext.User as MyFormsPrincipal<MyUserDataPrincipal>;
            if (user != null)
                return (user.IsInRole(Roles) || user.IsInUser(Users));

            return false;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            //驗證不經過,直接跳轉到相應頁面,注意:若是不使用如下跳轉,則會繼續執行Action方法
            filterContext.Result = new RedirectResult("http://www.baidu.com");
        }
    }

好了,四個類定義完成,接下來是使用

一、首先是登錄

        [HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
          //經過數據庫查詢驗證
var bll= new UserBll(); var userId = bll.Validate(model.UserName, model.Password, HttpContext.Request.UserHostAddress, HttpContext.Request.UserAgent); if (userId > 0) { //驗證成功,用戶名密碼正確,構造用戶數據(能夠添加更多數據,這裏只保存用戶Id) var userData = new MyUserDataPrincipal {UserId = userId}; //保存Cookie MyFormsAuthentication<MyUserDataPrincipal>.SetAuthCookie(model.UserName, userData, model.RememberMe); if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) { return Redirect(returnUrl); } else { return RedirectToAction("Index", "Home"); } } else { ModelState.AddModelError("", "提供的用戶名或密碼不正確。"); } } // 若是咱們進行到這一步時某個地方出錯,則從新顯示錶單 return View(model); }

 

2、登錄完成後,是驗證,驗證以前首先要得到客戶端的用戶數據(從以前設置的Cookie中解析)

  在全局文件:Global.asax 中添加下面代碼

        protected void Application_PostAuthenticateRequest(object sender, System.EventArgs e)
        {
            var formsIdentity = HttpContext.Current.User.Identity as FormsIdentity;
            if (formsIdentity != null && formsIdentity.IsAuthenticated && formsIdentity.AuthenticationType == "Forms")
            {
                HttpContext.Current.User =
                    MyFormsAuthentication<MyUserDataPrincipal>.TryParsePrincipal(HttpContext.Current.Request);
            }
        }

 這樣就從Request解析出了UserData,下面能夠用於驗證了

3、在須要驗證角色的Action上添加 [MyAuthorize] 特性

        [MyAuthorize(Roles = "User", Users = "bomo,toroto")]
        public ActionResult About()
        {
            return View();
        }

  當用戶訪問該Action時,調用 MyAuthorize 的 AuthorizeCore 方法進行驗證, 若是驗證成功,則繼續執行,若是驗證失敗,會調用 HandleUnauthorizedRequest方法作相應處理,在MyAuthorize 中能夠得到這裏定義的 RolesUsers 進行驗證

相關文章
相關標籤/搜索