NetCore MVC 权限设计

1.以前我们的权限主要靠手工录入到系统中,然后进行验证,这种方式不仅耗时,而且一旦按钮id 发生变动等情况 维护比较麻烦,现在我们采用直接从Controller中读取对应的action 进行设置权限,这样就不需要做过多维护以下是源码

 /// <summary>
    /// 控制器操作类 
    /// </summary>
    public class ControllerHelper
    {
        private const string All_ControllerActionCacheKey = "All_System_ControllerHelper_Actions_List";

        /// <summary>
        /// 获取所有页面的Action
        /// </summary>
        public static List<BasePermissionAttribute> AuthAttributes
        {
            get
            {
                return ApplicationEnvironments.CacheService.Get<List<BasePermissionAttribute>>(All_ControllerActionCacheKey, () =>
                {
                    return new ControllerHelper().GetAllActions();
                }, true);

            }
        }
       
        /// <summary>
        /// 获取单页面的Action
        /// </summary>
        /// <param name="areaName"></param>
        /// <param name="controllerName"></param>
        /// <returns></returns>
        public static List<BasePermissionAttribute> GetActionsByPage(string areaName,string controllerName) {
            
            if (AuthAttributes != null && AuthAttributes.Count > 0)
            {
                return AuthAttributes.Where(x=>x.AreaName.ToLower().Equals(areaName.ToLower())&&x.ControllerName.ToLower().Equals(controllerName.ToLower())).ToList();
            }
            return null;
        }

        /// <summary>
        /// 获取所有页面的Action
        /// </summary>
        private List<BasePermissionAttribute> GetAllActions()
        {
            #region 通过反射读取Action方法写入对应权限至集合
            List<BasePermissionAttribute> authAttributes = new List<BasePermissionAttribute>();
            //读取当前项目程序集中集成自AdminController的控制器
            var files = System.IO.Directory.GetFiles(AppContext.BaseDirectory, "*.Web.dll");
            if (files != null && files.Length > 0)
            {
                foreach (var file in files)
                {
                    var assembly = Assembly.LoadFrom(file);
                    var types = assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(BaseController))).ToList();
                  
                    //var now = DateTime.Now;

                    foreach (var type in types)
                    {
                        //获取所有action方法
                        GetControllerActions(type,ref authAttributes);
                    }
                }
            }
            return authAttributes;
            #endregion
        }

        /// <summary>
        /// 获取单个控制器中的Actions
        /// </summary>
        /// <param name="controller"></param>
        private void GetControllerActions(Type controller, ref List<BasePermissionAttribute> authAttributes)
        {
            var areaAttr= controller.GetCustomAttribute(typeof(AreaAttribute),true);
            string areaName = "";
            if (areaAttr != null)
            {
                areaName = (areaAttr as AreaAttribute).RouteValue;
            }
            var members = controller.GetMethods().Where(e => e.ReturnType.Name == nameof(ActionResult)
                       || e.ReturnType.Name == nameof(IActionResult)
                       || e.ReturnType.Name == nameof(JsonResult)
                       );
            string[] systemAction = {"index","forgrid" };
            foreach (var member in members)
            {
                if (systemAction.Contains(member.Name.ToLower()))
                {
                    continue;
                }
                //获取功能列表
                var attr = member.GetCustomAttribute(typeof(BasePermissionAttribute), true) ;
                if (attr == null)
                    continue;
                var auth = attr as BasePermissionAttribute;
                if (string.IsNullOrWhiteSpace(auth.ActionCode)|| !string.IsNullOrWhiteSpace(auth.ActionName) || auth.IsParent|| auth.NoAccess)
                {
                    continue;
                }
                auth.AreaName = areaName;
                if (string.IsNullOrWhiteSpace(auth.ActionName))
                {
                    auth.ActionName = member.Name;
                }
                auth.ControllerName = controller.Name.Replace("Controller", "");
                //功能对应的二级菜单
                authAttributes.Add(auth);
            }
            
        }
    }

2.BasePermissionAttribute权限基类,

主要用于定义action 访问属性,由于在底层需要引用该类方便存储读取controller中的action 所以需要这个基类,如果项目这个类放在业务层是不需要分开的

public class BasePermissionAttribute :Attribute, IAsyncAuthorizationFilter 
    {
        /// <summary>
        /// get请求是否需要验证权限 默认是
        /// </summary>
        public bool IsGet { get; set; }
        /// <summary>
        /// post请求是否需要验证权限 默认是
        /// </summary>
        public bool IsPost { get; set; }

        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 与其它ActionName权限一样
        /// </summary>
        public string ActionCode { get; set; }

        /// <summary>
        /// Action名称
        /// </summary>
        public string ActionName { get; set; }

        /// <summary>
        /// 域名称
        /// </summary>
        public string AreaName { get; set; }
        /// <summary>
        /// 控制器名称
        /// </summary>

        public string ControllerName { get; set; }

        /// <summary>
        /// 是否继承controller  Index访问权限
        /// </summary>
        public bool IsParent { get; set; }

        /// <summary>
        /// 不允许访问
        /// </summary>
        public bool NoAccess { get; set; }
        //public PermissionAttribute()
        //{
        //    IsGet = true;
        //    IsPost = true;
        //}
        public BasePermissionAttribute() {
            IsGet = true;
            IsPost = true;
            IsParent = false;
        }
        public BasePermissionAttribute(string code,string description)
        {
            IsGet = true;
            IsPost = true;
            IsParent = false;
            ActionCode = "BTN" + code;
            Description = description;
        }
       
        /// <summary>
        /// 输出错误信息
        /// </summary>
        /// <param name="filterContext"></param>
        /// <param name="strError"></param>
        public void WriteResult(AuthorizationFilterContext filterContext,  string strError)
        {
            var areaName = "";
            var actionName = filterContext.RouteData.Values["Action"].ToString();
            var controllerName = filterContext.RouteData.Values["controller"].ToString();
            if (filterContext.RouteData.DataTokens["area"] != null)
            {
                areaName = filterContext.RouteData.DataTokens["area"].ToString();
            }
            //new LogErrorService().Save((!string.IsNullOrEmpty(areaName)?areaName+"/"+controllerName:controllerName),actionName,strError,strError);
            if (AppHttpContext.IsPost&&AppHttpContext.IsAjax)
            {
                filterContext.HttpContext.Response.StatusCode = 200;
                filterContext.Result = new JsonResult(AjaxResult.Error(strError, -100));
            }
            else
            {
                var view = new ViewResult();
                view.ViewName = "~/Views/Home/Error.cshtml";
                view.ViewData = new Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary(new BaseController().ViewData);
                view.ViewData["Message"] = strError;
                view.ViewData["Exception"] = new Exception(strError);
                filterContext.Result = view;

            }

        }

        public virtual Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
        {
            return Task.CompletedTask;
        }

3.权限的具体实现

public class PermissionAttribute : BasePermissionAttribute
    {
        public PermissionAttribute():base()
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="code">权限标识(controller中请勿重复)</param>
        /// <param name="description">描述</param>
        public PermissionAttribute(string actionCode, string description) : base(actionCode, description)
        {
        }
        public override Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
        {
            //匿名标识 无需验证
            if (filterContext.Filters.Any(e => (e as AllowAnonymousAttribute) != null))
                return Task.CompletedTask;
            if ((AppHttpContext.IsPost && !IsPost)||(!AppHttpContext.IsPost && !IsGet))
            {
                return Task.CompletedTask;
            }
            if (NoAccess)
            {
                WriteResult(filterContext, "该接口不允许访问");
                return Task.CompletedTask;
            }
            
            if (!AppHttpContext.Current.User.Identity.IsAuthenticated)
            {
                WriteResult(filterContext, "未登录,无权访问");
                return Task.CompletedTask;
            }
            var userEntity = ApplicationEnvironments.DefaultSession.GetUser<UserEntity>();
            if (userEntity == null)
            {
                WriteResult(filterContext, "对不起,您无权访问");
                return Task.CompletedTask;
            }
            //获取请求的区域,控制器,action名称
            this.AreaName = string.IsNullOrWhiteSpace(this.AreaName) ? filterContext.RouteData.Values["area"]?.ToString() : this.AreaName;
            this.ControllerName = string.IsNullOrWhiteSpace(this.ControllerName) ? filterContext.RouteData.Values["controller"]?.ToString() : this.ControllerName;
            this.ActionName = string.IsNullOrWhiteSpace(this.ActionName) ? filterContext.RouteData.Values["action"]?.ToString() : this.ActionName;
            if (IsParent)
            {
                this.ActionName = "Index";
            }
            var isPermit = false;
            if (string.IsNullOrWhiteSpace(ControllerName) || ControllerName.ToLower().Equals("home"))
            {
                ControllerName = "";
            }
            if (string.IsNullOrWhiteSpace(ActionName) || ActionName.ToLower().Equals("index"))
            {
                ActionName = "";
            }
            string routeUrl = "";
            routeUrl = (!string.IsNullOrWhiteSpace(AreaName) ? AreaName + "/" : "").ToLower();
            if(!string.IsNullOrWhiteSpace(ControllerName))
            {
                routeUrl += ControllerName.ToLower() + (!string.IsNullOrWhiteSpace(ActionName) ?  "/" : "");
            }

            routeUrl += ActionName.ToLower();

            var isUmPermit = userEntity.UnPermission.Where(x => x.RouteUrl.ToLower().Equals(routeUrl)).FirstOrDefault() != null;
            if (!isUmPermit)
            {
                isPermit = userEntity.Permission.Where(x => x.RouteUrl.ToLower().Equals(routeUrl)).FirstOrDefault() != null;
                if (isPermit)
                {
                    return Task.CompletedTask;
                }
            }

            WriteResult(filterContext, "对不起,您无权访问");
            return Task.CompletedTask;
        }
    }

4.在action 上增加如下代码 即可

[Permission("Code", "名称")]

猜你喜欢

转载自my.oschina.net/u/3049482/blog/2965711
今日推荐