首页 > 代码库 > asp.net mvc 全局权限过滤器及继成权限方法

asp.net mvc 全局权限过滤器及继成权限方法

全局权限过滤器

//-----------------------------------------------------------------------// <copyright file="PermissionFilter.cs" company="STO EXPRESS, Ltd.">//     Copyright (c) 2015 , All rights reserved.// </copyright>//-----------------------------------------------------------------------using System;using System.Collections.Generic;using System.Linq;using System.Web.Mvc;namespace DotNet.MVCInfrastructure.Filter{    using DotNet.Model;    using DotNet.MVCInfrastructure.Attributes;    using DotNet.MVCInfrastructure.Common;    using DotNet.MVCInfrastructure.Enumerations;    using DotNet.MVCInfrastructure.Models;    using DotNet.Utilities;    using DotNet.Business;    /// <summary>    /// 身份验证过滤器    ///     /// 1、匿名访问    /// 2、登录就可以访问    /// 3、需要验证是否有菜单或按钮或资源的权限    ///     ///     /// 修改纪录    ///     /// 2015-10-11 版本:1.0 SongBiao 创建文件。       ///     /// <author>    ///     <name>SongBiao</name>    ///     <date>2015-10-11</date>    /// </author>    /// </summary>    public class CheckPermissionFilter : IAuthorizationFilter    {        /// <summary>        /// 认证和授权是两个方面        /// </summary>        /// <param name="filterContext"></param>        public void OnAuthorization(AuthorizationContext filterContext)        {            string pageUrl = filterContext.HttpContext.Request.Url == null ? "$$#$$" : filterContext.HttpContext.Request.Url.AbsolutePath; //OperateContext.GetThisPageUrl(false);            //NLogHelper.Debug("CheckPermissionFilter:" + DateTime.Now + ",pageUrl=" + pageUrl);            if (filterContext == null)            {                throw new ArgumentNullException("filterContext");            }            if (filterContext.HttpContext.Request.Url == null)            {                throw new ArgumentNullException("filterContext");            }            // 是否是Ajax请求            var bAjax = filterContext.HttpContext.Request.IsAjaxRequest();            // 注意 所有允许匿名访问的Controller,Action 都要设置匿名访问标签            // 只对 Action 做判断            // 判断 控制器 是否可以匿名访问            var controllerAnonymous = filterContext.Controller.GetType().GetCustomAttributes(typeof(AllowAnonymousAttribute), true) as IEnumerable<AllowAnonymousAttribute>;            // 先判断控制器是否可以匿名访问            if ((controllerAnonymous != null && controllerAnonymous.Any()))            {                // 再检查Action 是否有登录检查标签                var checkLoginActionAttr = filterContext.ActionDescriptor.GetCustomAttributes(typeof(CheckLoginAttribute), true) as IEnumerable<CheckLoginAttribute>;                if (checkLoginActionAttr != null && checkLoginActionAttr.Any())                {                }                else                {                    // 如果没有 让他可以继续访问 因为把Controller 设置为 AllowAnonymous 了                    return;                }                // 匿名就可以访问 无需验证登录状态                //return;            }            // 判断 Action 是否可以匿名访问            var actionAnonymous = filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true) as IEnumerable<AllowAnonymousAttribute>;            if (actionAnonymous != null && actionAnonymous.Any())            {                // 匿名就可以访问 无需验证登录状态                return;            }            // 1、允许匿名访问 用于标记在授权期间要跳过 AuthorizeAttribute 的控制器和操作的特性             // 2017-03-06 检查OpenId 只需传来openId            if (!string.IsNullOrWhiteSpace(filterContext.HttpContext.Request["openId"]))            {                string openId = filterContext.HttpContext.Request["openId"];                UserLogOnResult userLogOnResult = Business.Utilities.LogOnByOpenId(openId, true);                if (userLogOnResult != null && !string.IsNullOrEmpty(userLogOnResult.StatusCode) &&                    userLogOnResult.StatusCode == Status.OK.ToString())                {                    // 用户状态存储                    OperateContext.Current.AddCurrent(userLogOnResult.UserInfo);                }            }            else if (!string.IsNullOrWhiteSpace(filterContext.HttpContext.Request["AuthorizationCode"]))            {                // 2017-05-23 检查传过来的AuthorizationCode 支持code跳转登录                string authorizationCode = filterContext.HttpContext.Request["AuthorizationCode"];                string openId;                if (BaseUserManager.VerifyAuthorizationCode(null, authorizationCode, out openId))                {                    // 用户状态存储                    UserLogOnResult userLogOnResult = Business.Utilities.LogOnByOpenId(openId, true);                    if (userLogOnResult != null && !string.IsNullOrEmpty(userLogOnResult.StatusCode) &&                        userLogOnResult.StatusCode == Status.OK.ToString())                    {                        // 用户状态存储                        OperateContext.Current.AddCurrent(userLogOnResult.UserInfo);                    }                }            }            // 2、判断是否登录或登录已超时 需要重新登录            if (OperateContext.Current.UserInfo == null)            {                // 用户状态已过期                // 判断请求是否是Ajax请求                if (bAjax)                {                    BusinessResultBase result = new BusinessResultBase();                    result.Title = "未登录或登录已超时";                    result.Status = false;                    result.StatusCode = BusinessStatusCode.LoginTimeOut.ToString();                    result.StatusMessage = "请重新登录系统。";                    var jsonResult = new JsonResult();                    jsonResult.Data = result;                    jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;                    filterContext.Result = jsonResult;                }                else                {                    //filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Area="",Controller = "Account", action = "Login" }));                    filterContext.Result = new RedirectResult(BusinessSystemInfo.LoginUrl + "?returnUrl=" + pageUrl);                }            }            else            {                // 用户状态未过期                // 3、拒绝某个账号登录当前系统 判断用户是否在拒绝登录的子系统中                //if (OperateContext.Current.IsDenyVisit())                //{                //    if (bAjax)                //    {                //        BusinessResultBase result = new BusinessResultBase();                //        result.Title = "拒绝访问当前系统";                //        result.Status = false;                //        result.StatusCode = BusinessStatusCode.AccessDeny.ToString();                //        result.StatusMessage = "您的账号不允许访问当前系统。";                //        var jsonResult = new JsonResult();                //        jsonResult.Data = http://www.mamicode.com/result;>//        filterContext.Result = jsonResult;                //    }                //    else                //    {                //        filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Controller = "Prompt", action = "DenyAccess", bAjaxReq = false, message = "没有获取您拥有的权限菜单,请尝试重新登录。" }));                //    }                //}                //else                 if (OperateContext.Current.UserInfo.IsAdministrator)                {                    // 超级管理员不检查权限了                    return;                }                else                {                    // 4、判断用户是否能够访问当前的controller,action                    // 5、判断登录状态 根据Controller或Action上的标签 某些功能只需判断是否登录                    // 判断Controller上是否有CheckLoginAttribute标签 只需要登录就可以访问                    // 实际上检查登录也不好,应该检查改Action是否是公开的  上面做为临时用  某些系统没有菜单或者没有配置的Action可以这样做  否则都必须配置菜单                    // 判断Controller上是否有CheckLoginAttribute标签 只需要登录就可以访问的                    var checkLoginControllerAttr = filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(CheckLoginAttribute), true) as IEnumerable<CheckLoginAttribute>;                    if (checkLoginControllerAttr != null && checkLoginControllerAttr.Any())                    {                        // 否则 没有设置 CheckLogin 标签的 就要验证 向下执行  到这里 除了设置 CheckLogin 的action 都要检查菜单访问权限                        return;                    }                    // 判断action上是否有CheckLoginAttribute标签 只需要登录就可以访问的                    var checkLoginActionAttr = filterContext.ActionDescriptor.GetCustomAttributes(typeof(CheckLoginAttribute), true) as IEnumerable<CheckLoginAttribute>;                    if (checkLoginActionAttr != null && checkLoginActionAttr.Any())                    {                        return;                    }                    // 6、有些要判断是否有某个controller或 action的权限  通过获取的权限菜单进行比较                    // 用户具有的菜单                    var moduleList = OperateContext.Current.UserPermission;//.GetPermissionList(false);                    if (moduleList == null || !moduleList.Any())                    {                        // 没有获取到任何菜单                        if (bAjax)                        {                            BusinessResultBase result = new BusinessResultBase();                            result.Title = "没有访问权限";                            result.Status = false;                            result.StatusCode = BusinessStatusCode.AccessDeny.ToString();                            result.StatusMessage = "没有获取到任何菜单,请尝试重新登录或咨询系统开发人员。";                            var jsonResult = new JsonResult();                            jsonResult.Data = result;                            jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;                            filterContext.Result = jsonResult;                            //var jsonResult = new JsonResult { Data = http://www.mamicode.com/new BaseModels { IsError = true, ErrMsg ="请先登录!", ErrCode = "unlogin" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };                            //filterContext.RequestContext.HttpContext.Response.Write(JsonConvert.SerializeObject(result));                            //filterContext.RequestContext.HttpContext.Response.End();                        }                        else                        {                            //filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Area = "", Controller = "Error", action = "NoAccess", bAjaxReq = false, message = "没有获取您拥有的权限菜单,请尝试重新登录。" }));                            filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Area = "", Controller = "Error", action = "NoAccess", bAjaxReq = false, message = "没有获取到任何菜单,您没有权限访问当前内容:" + pageUrl + "" }));                        }                    }                    else                    {                        // 获取到菜单,进行比较                        //var controllerName = (filterContext.RouteData.Values["controller"]).ToString().ToLower();                        //var actionName = (filterContext.RouteData.Values["action"]).ToString().ToLower();                        //var areaName = (filterContext.RouteData.DataTokens["area"] ?? "").ToString().ToLower();                        /* 这个方式需要在controller或action上人为添加一个Attribute,没有必要,直接可以取到当前的controller和actionName                        // 用于标记在授权期间需要CustomerResourceAttribute 的操作的特性                        var attNames = filterContext.ActionDescriptor.GetCustomAttributes(typeof(CustomerResourceAttribute), true) as IEnumerable<CustomerResourceAttribute>;                        // 判断用户的权限菜单中的code是否与控制器上标示的资源的code一致                        var joinResult = (from aclEntity in moduleList                                          join attName in attNames on aclEntity.Code equals attName.ResourceName                                          select attName).Any();                        if (!joinResult)                        */                        // 子系统菜单配置时,子系统的菜单code不能重复                        // 同时支持通过访问地址,Code来判断                        // 主要是要在全局过滤器里添加   filters.Add(new CheckPermissionFilter());                        // 检查地址是否与当前Action的地址一致                        var modules = from module in moduleList                                      where                                      string.Equals(module.NavigateUrl, pageUrl, StringComparison.OrdinalIgnoreCase)                                      //|| string.Equals(module.Code, controllerName, StringComparison.OrdinalIgnoreCase)                                      //|| string.Equals(module.Code, actionName, StringComparison.OrdinalIgnoreCase)                                      select module;                        //string results = JsonHelper.SerializeObject(moduleList);                        if (!modules.Any())                        {                            // 菜单没有配置或者没有权限                            if (bAjax)                            {                                BusinessResultBase result = new BusinessResultBase();                                result.Title = "没有访问权限";                                result.Status = false;                                result.StatusCode = BusinessStatusCode.AccessDeny.ToString();                                result.StatusMessage = "在您的权限中,您没有权限访问当前内容:" + pageUrl + "";                                var jsonResult = new JsonResult();                                jsonResult.Data = result;                                jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;                                filterContext.Result = jsonResult;                            }                            else                            {                                filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Area = "", Controller = "Error", action = "NoAccess", bAjaxReq = false, message = "在您的权限中,您没有权限访问当前内容:" + pageUrl + "" }));                            }                        }                        else                        {                            return;                        }                    }                }            }        }    }}

放在全局过滤器中即可,实现全部Action的访问控制

    public class FilterConfig    {        public static void RegisterGlobalFilters(GlobalFilterCollection filters)        {            // filters.Add(new HandleErrorAttribute());            filters.Add(new ElmahHandleErrorAttribute());            // 全局身份验证过滤器 更方便             filters.Add(new CheckPermissionFilter());        }    }

 

继承权限的使用场景:

在某些情况下,只要具有其中一个Action的权限,那么跟他关联的Action权限可以不用配置,
如在查询场景中,配置了用户访问 Public ActionResult Index()主页面的权限,查询时请求的是 Public ActionResult List(......)
那么在List上加上标签
[CheckActionPermission("/XXXArea/XXXController/Index")]
Public ActionResult List(......)
这样就可以了,
CheckActionPermission里的参数是要继续的Action的菜单路径。
避免为List再配置菜单,授权。
另外象添加页面,保存的action Save可以不必配置菜单授权,只要在上面配置[CheckActionPermission("/XXXArea/XXXController/Add")]即可。既然能看到添加界面,那么保存操作就应该是允许的。

//-----------------------------------------------------------------------// <copyright file="CheckActionPermissionAttribute" company="STO, Ltd.">//     Copyright (c) 2017 , All rights reserved.// </copyright>//-----------------------------------------------------------------------using System;using System.Linq;using System.Web.Mvc;namespace DotNet.MVCInfrastructure.Attributes{    using DotNet.MVCInfrastructure.Enumerations;    using DotNet.MVCInfrastructure.Models;    using DotNet.MVCInfrastructure.Common;    using DotNet.Utilities;    /// <summary>    /// CheckActionPermissionAttribute    /// 记权限拦截    ///     /// 修改纪录    ///     /// 2017-07-21 版本:1.0 SongBiao 创建文件。         ///     /// <author>    ///     <name>SongBiao</name>    ///     <date>2017-07-21</date>    /// </author>    /// </summary>    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]    public class CheckActionPermissionAttribute : ActionFilterAttribute, IActionFilter    {        /// <summary>        /// 检查的Module        /// </summary>        private string Module;        /// <summary>        /// 构造函数 module表示检查哪个菜单的权限即可        /// 如某些列表,只需要检查主页面的菜单权限即可        /// CheckActionPermission["/Headquarters/DaTouBiMain/Index"]        /// </summary>        /// <param name="module"></param>        public CheckActionPermissionAttribute(string module)        {            Module = module;        }        FilterContextInfo fcinfo;        /// <summary>        /// 在执行操作方法之前由 ASP.NET MVC 框架调用。        /// </summary>        /// <param name="filterContext"></param>        public override void OnActionExecuting(ActionExecutingContext filterContext)        {            string pageUrl = filterContext.HttpContext.Request.Url == null ? "$$#$$" : filterContext.HttpContext.Request.Url.AbsolutePath; //OperateContext.GetThisPageUrl(false);            var bAjax = filterContext.HttpContext.Request.IsAjaxRequest();            if (string.IsNullOrWhiteSpace(Module))            {                if (bAjax)                {                    BusinessResultBase result = new BusinessResultBase();                    result.Title = "参数值不可以为空";                    result.Status = false;                    result.StatusCode = BusinessStatusCode.AccessDeny.ToString();                    result.StatusMessage = "CheckActionPermission参数值不可以为空。";                    var jsonResult = new JsonResult();                    jsonResult.Data = result;                    jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;                    filterContext.Result = jsonResult;                }                else                {                    filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Area = "", Controller = "Error", action = "NoAccess", bAjaxReq = false, message = "CheckActionPermission参数值不可以为空" }));                }            }            else            {                if (OperateContext.Current.UserInfo == null)                {                    if (bAjax)                    {                        BusinessResultBase result = new BusinessResultBase();                        result.Title = "未登录或登录已超时";                        result.Status = false;                        result.StatusCode = BusinessStatusCode.AccessDeny.ToString();                        result.StatusMessage = "未登录或登录已超时,请重新登录系统。";                        var jsonResult = new JsonResult();                        jsonResult.Data = result;                        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;                        filterContext.Result = jsonResult;                    }                    else                    {                        filterContext.Result = new RedirectResult(BusinessSystemInfo.LoginUrl + "?returnUrl=" + pageUrl);                    }                }                else                {                    fcinfo = new FilterContextInfo(filterContext);                    string areaName = fcinfo.AreaName;                    string controllerName = fcinfo.ControllerName;                    string actionName = fcinfo.ActionName;                    // 当前访问的                    string currentModule = "/";                    if (!string.IsNullOrWhiteSpace(areaName))                    {                        currentModule = currentModule + areaName;                    }                    if (!string.IsNullOrWhiteSpace(controllerName))                    {                        currentModule = currentModule + "/" + controllerName;                    }                    if (!string.IsNullOrWhiteSpace(actionName))                    {                        currentModule = currentModule + "/" + actionName;                    }                    var moduleList = OperateContext.Current.UserPermission;                    // 比较Module在菜单中是否存在 如列表的权限只需要验证主界面的权限即可                    var modules = from module in moduleList                                  where                                  !string.IsNullOrWhiteSpace(module.NavigateUrl) && string.Equals(module.NavigateUrl.Trim(), Module.Trim(), StringComparison.OrdinalIgnoreCase)                                  //|| string.Equals(module.Code, controllerName, StringComparison.OrdinalIgnoreCase)                                  //|| string.Equals(module.Code, actionName, StringComparison.OrdinalIgnoreCase)                                  select module;                    //var modules = moduleList.Where(t => string.Equals(t.NavigateUrl, Module, StringComparison.OrdinalIgnoreCase));                    if (modules == null || !modules.Any())                    {                        // 菜单没有配置或者没有权限                        if (bAjax)                        {                            BusinessResultBase result = new BusinessResultBase();                            result.Title = "没有访问权限";                            result.Status = false;                            result.StatusCode = BusinessStatusCode.AccessDeny.ToString();                            result.StatusMessage = "在您的权限中,您没有权限访问当前内容:" + currentModule + ",需要授予用户对:" + Module + "的权限。";                            var jsonResult = new JsonResult();                            jsonResult.Data = result;                            jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;                            filterContext.Result = jsonResult;                        }                        else                        {                            filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Area = "", Controller = "Error", action = "NoAccess", bAjaxReq = false, message = "在您的权限中,您没有权限访问当前内容:" + currentModule + ",需要授予用户对:" + Module + "的权限。" }));                        }                    }                    else                    {                        return;                    }                }            }        }        /// <summary>        /// 在执行操作方法后由 ASP.NET MVC 框架调用。        /// </summary>        /// <param name="filterContext"></param>        public override void OnActionExecuted(ActionExecutedContext filterContext)        {            base.OnActionExecuted(filterContext);        }        /// <summary>        ///  OnResultExecuted 在执行操作结果后由 ASP.NET MVC 框架调用。        /// </summary>        /// <param name="filterContext"></param>        public override void OnResultExecuted(ResultExecutedContext filterContext)        {            base.OnResultExecuted(filterContext);        }        /// <summary>        /// OnResultExecuting 在执行操作结果之前由 ASP.NET MVC 框架调用。        /// </summary>        /// <param name="filterContext"></param>        public override void OnResultExecuting(ResultExecutingContext filterContext)        {            base.OnResultExecuting(filterContext);        }        public class FilterContextInfo        {            public FilterContextInfo(ActionExecutingContext filterContext)            {                #region 获取链接中的字符                DomainName = filterContext.HttpContext.Request.Url.Authority;                AreaName = (filterContext.RouteData.DataTokens["area"] ?? "").ToString();                ControllerName = filterContext.RouteData.Values["controller"].ToString();                ActionName = filterContext.RouteData.Values["action"].ToString();                #endregion            }            /// <summary>            /// 获取域名            /// </summary>            public string DomainName { get; set; }            /// <summary>            /// 获取 controllerName 名称            /// </summary>            public string AreaName { get; set; }            /// <summary>            /// 获取 controllerName 名称            /// </summary>            public string ControllerName { get; set; }            /// <summary>            /// 获取ACTION 名称            /// </summary>            public string ActionName { get; set; }        }    }}

 

asp.net mvc 全局权限过滤器及继成权限方法