zoukankan      html  css  js  c++  java
  • 【3】.net MVC 使用IPrincipal进行Form登录即权限验证

    1.在MVC项目中添加用户类,可以根据实际项目需求添加必要属性

    public class UserData
        {
            /// <summary>
            /// ID
            /// </summary>
            public int UserId { get; set; }
    
            /// <summary>
            /// 用户名
            /// </summary>
            public string UserName { get; set; }
    
            /// <summary>
            /// 角色ID列表
            /// </summary>
            public List<int> Roles { get; set; }
        }

    2.添加类Principal实现IPrincipal接口

        public class Principal : IPrincipal
        {
            public IIdentity Identity { get; private set;}
    
            public UserData Account { get; set; }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="ticket"></param>
            /// <param name="account"></param>
            public Principal(FormsAuthenticationTicket ticket, UserData account)
            {
                if (ticket == null)
                    throw new ArgumentNullException("ticket");
                if (account == null)
                    throw new ArgumentNullException("UserData");
    
                this.Identity = new FormsIdentity(ticket);
                this.Account = account;
            }
    
            public bool IsInRole(string role)
            {
                if (string.IsNullOrEmpty(role))
                    return true;
                if (this.Account == null || this.Account.Roles == null)
                    return false;
                return role.Split(',').Any(q => Account.Roles.Contains(int.Parse(q)));
            }
        }


    IPrincipal接口有对象Identity已经需要实现验证角色方法IsInRole()。在我们的实现类中添加了"用户信息(UserData)"属性Account。

    构造函数中进行了初始化,第一个对象为Form验证的票据对象,下面ticket会携带用户信息一起保存进cookie中。

    3.创建存储cookie和读取cookie的类

        /// <summary>
        /// 写入cookie和读取cookie
        /// </summary>
        public class HttpFormsAuthentication
        {
            //将用户信息通过ticket加密保存到cookie
            public static void SetAuthenticationCoolie(UserData account, int rememberDay = 0)
            {
                if (account == null)
                    throw new ArgumentNullException("account");
    
                //序列化account对象
                string accountJson = JsonConvert.SerializeObject(account);
                //创建用户票据
                var ticket = new FormsAuthenticationTicket(1, account.UserName, DateTime.Now, DateTime.Now.AddDays(rememberDay), false, accountJson);
                //加密
                string encryptAccount = FormsAuthentication.Encrypt(ticket);
    
                //创建cookie
                var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptAccount)
                {
                    HttpOnly = true,
                    Secure = FormsAuthentication.RequireSSL,
                    Domain = FormsAuthentication.CookieDomain,
                    Path = FormsAuthentication.FormsCookiePath
                };
    
                if (rememberDay > 0)
                    cookie.Expires = DateTime.Now.AddDays(rememberDay);
    
                //写入Cookie
                HttpContext.Current.Response.Cookies.Remove(cookie.Name);
                HttpContext.Current.Response.Cookies.Add(cookie);
            }
    
            //获取cookie并解析出用户信息
            public static Principal TryParsePrincipal(HttpContext context)
            {
                if (context == null)
                    throw new ArgumentNullException("context");
                HttpRequest request = context.Request;
                HttpCookie cookie = request.Cookies[FormsAuthentication.FormsCookieName];
                if (cookie == null || string.IsNullOrEmpty(cookie.Value))
                {
                    return null;
                }
                //解密coolie值
                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
    
                UserData account = JsonConvert.DeserializeObject<UserData>(ticket.UserData);
                return new Principal(ticket, account);
            }
    
        }


    存储cookie时将用户信息序列化后的字符串accountJson由ticket其携带加密后保存入cookie中,具体的accountJson被赋值给FormsAuthenticationTicket的UserData属性。

    可看到解析时将ticket.UserData反序列化后得到了原始的用户信息对象,然后生成Principal对象。

    解析cookie得到Principal对象的方法TryParsePrincipal,下面会在发起请求时用到,而返回的Principal对象被赋值给HttpContext.User。

    4.在Global.asax中注册Application_PostAuthenticateRequest事件,保证权限验证前将cookie中的用户信息取出赋值给User

    protected void Application_PostAuthenticateRequest(object sender, System.EventArgs e)
            {
                HttpContext.Current.User =
                    HttpFormsAuthentication.TryParsePrincipal(HttpContext.Current);
            }

    5.集成AuthorizeAttribute特性类并重写AuthorizeCore,HandleUnauthorizedRequest方法

        public class FormAuthorizeAttribute : AuthorizeAttribute
        {
            /// <summary>
            /// 先进入此方法,此方法中会调用 AuthorizeCore 验证逻辑,验证不通过会调用 HandleUnauthorizedRequest 方法
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                base.OnAuthorization(filterContext);
            }
    
            /// <summary>
            /// 权限验证
            /// </summary>
            /// <param name="httpContext"></param>
            /// <returns></returns>
            protected override bool AuthorizeCore(HttpContextBase httpContext)
            {
                var user = httpContext.User as Principal;
                if (user != null)
                    return user.IsInRole(base.Roles);
                return false;
            }
    
            protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
            {
                //验证不通过,直接跳转到相应页面,注意:如果不是哟娜那个以下跳转,则会继续执行Action方法
                filterContext.Result = new RedirectResult("~/Login/Index");
            }
        }


    AuthorizeCore与HandleUnauthorizedRequest方法均是在方法OnAuthorization中调用,AuthorizeCore验证不通过才会调用HandleUnauthorizedRequest方法。

    将验证代码在AuthorizeCore中实现,验证不通过的逻辑在HandleUnauthorizedRequest方法中实现。

    6.添加LoginController实现登录逻辑

    namespace MVCAuthorizeTest.Controllers
    {
        public class LoginController : Controller
        {
            [AllowAnonymous]
            // GET: Login
            public ActionResult Index(string returnUrl)
            {
                ViewBag.ReturnUrl = returnUrl;
                return View();
            }
    
            [HttpPost]
            [AllowAnonymous]
            public ActionResult Index(string name, string password, bool rememberMe, string returnUrl)
            {
                var account = new UserData()
                {
                    UserName = name,
                    UserId = 110,
                    Roles = new List<int>() { 1, 2, 3 }
                };
                HttpFormsAuthentication.SetAuthenticationCoolie(account, rememberMe ? 7 : 0);
                if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return RedirectToAction("Index", "Home");
                }
            }
    
            // POST: /Account/LogOff
            [HttpPost]
            public ActionResult LogOff()
            {
                System.Web.Security.FormsAuthentication.SignOut();
                return RedirectToAction("Index", "Home");
            }
        }
    }

    7.对需要验证的controller或action添加特性标签

        [FormAuthorize(Roles = "1,2")]
        public class HomeController : Controller
        {
            [FormAuthorize]
            public ActionResult Index()
            {
                return View();
            }
        }


    如图

    8.在添加FilterConfig中添加全局注册filter,减少每个action分别设置。如果有不需要验证的页面,添加[AllowAnonymous]特性即可

        public class FilterConfig
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
                //全局注册filter
                filters.Add(new FormAuthorizeAttribute());
            }
        }



  • 相关阅读:
    JS伪3D 图形透视效果
    源码安装apache及配置转发
    SpringSecutiry权限管理手册
    解决SMARTFORMS 中table 控件单行跨页的问题
    Cluster Table
    uva-133 The Dole Queue
    第三届蓝桥杯C++本科B组决赛解题报告(更新中)
    uva-673 Parentheses Balance
    VS2010不能编译SQLServer2005的Microsoft.SQLServer.ManagedDTS.dll的解决方法
    IOS设计模式学习(21)享元
  • 原文地址:https://www.cnblogs.com/pengdylan/p/6407479.html
Copyright © 2011-2022 走看看