朴素的标题:MVC中权限管理实践


  基于MVC的web项目最好的权限控制方式我认为是对Action的控制实现思路记录于此,权限管理分成两个部分授权、认证。

一、授权

  1、读取当前项目中的所有需要控制的Action 

        /// 
        /// 获取当前程序集内的所有Action
        /// 
        /// 当前程序集内的所有Action
        /// author:lorne date:2016-01-13
        public List GetAllAction()
        {
            var actions = new List();
            var assembly = Assembly.GetExecutingAssembly();//获取当前程序集

            #region 读取XML获取Action说明
            Dictionary<string, string> notes = new Dictionary<string, string>();
            try
            {
                //读取程序集的XML文件
                var doc = new XmlDocument();
                doc.Load(Server.MapPath(string.Format("~/bin/{0}.xml", assembly.FullName.Substring(0, assembly.FullName.IndexOf(",")))));
                var membersInfo = doc.FirstChild["members"];

                JArray members = (JArray)JsonConvert.DeserializeObject(JsonConvert.SerializeXmlNode(doc.LastChild["members"]))["members"]["member"];
                foreach (var item in members)
                {
                    //以key-value形式存储
                    notes.Add(item.Value<string>("@name"), item.Value<string>("summary").Trim());
                }
            }
            catch (Exception)
            {
            }
            #endregion

            foreach (var type in assembly.GetTypes())
            {
                if (type.BaseType == typeof(Controller))//取出Controller
                {
                    var methods = type.GetMethods();
                    foreach (var method in methods)
                    {
                        if (method.ReturnType == typeof(ActionResult) || (method.ReturnType.BaseType != null && method.ReturnType.BaseType == typeof(ActionResult)))//取出Action
                        {
                            //允许匿名访问的不计入
                            if (method.GetCustomAttributes(typeof(AllowAnonymousAttribute)).Count() == 0)
                            {
                                var info = new ActionInfo();

                                info.Action = method.Name;
                                info.ActionDesc = notes.ContainsKey(string.Format("M:{0}.{1}.{2}", type.Namespace, type.Name, method.Name)) ? notes[string.Format("M:{0}.{1}.{2}", type.Namespace, type.Name, method.Name)] : "";
                                info.Controller = type.FullName;
                                info.ControllerDesc = notes.ContainsKey(string.Format("T:{0}.{1}", type.Namespace, type.Name)) ? notes[string.Format("T:{0}.{1}", type.Namespace, type.Name)] : "";

                                actions.Add(info);
                            }
                        }
                    }
                }
            }
            return actions;
        }

   2、保存授权设置,这个没有具体的实现,应该不会有太大的难度

二、认证

  1、使用过滤器(继承ActionFilterAttribute)处理Action请求,重写OnActionExecuting

public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //获取当前用户所拥有的权限
            List right = new List() { new ActionInfo() { Action = "A1", Controller = "RBAC.Controllers.AController" }, new ActionInfo() { Action = "A2", Controller = "RBAC.Controllers.AController" } };

            //白名单
            var whiteAction = GetWhiteAction();

            //获取用户要请求的页面
            ActionInfo context = new ActionInfo() { Action = filterContext.ActionDescriptor.ActionName, Controller = filterContext.Controller.ToString() };

            //判断是否有权访问
            if (!(whiteAction.Any(r => r.Action.Equals(context.Action, StringComparison.CurrentCultureIgnoreCase) && r.Controller.Equals(context.Controller, StringComparison.CurrentCultureIgnoreCase)) || right.Any(r => r.Action.Equals(context.Action, StringComparison.CurrentCultureIgnoreCase) && r.Controller.Equals(context.Controller, StringComparison.CurrentCultureIgnoreCase))))
            {
                filterContext.HttpContext.Response.Redirect("/Main/Msg");
            }
        }

  2、在 Global中注册过滤器

     GlobalFilters.Filters.Add(new AuthFilter());

  3、给一些不需要授权的Action加上特性[AllowAnonymous],当然也可以自定义其他的特性

        [AllowAnonymous]
        public ActionResult Msg()
        {
            return View();
        }

 

  由此基本完成,也可以下载源码参考下。