• Lind.DDD.Manager里菜单权限的设计


    回到目录

    对于一个后台管理系统来说,你的权限设计与安全是重中之重,当你为一个权限分配一些菜单后,当这个权限的用户没有菜单权限时,这个菜单的URL是不可以被用户访问的,而在之前的设计中,没有考虑到这点,所以本次Lind.DDD.Manager的升级中,需要把这块完善一下,将会在8月的Lind.DDD中奉献给大家,敬请期待!

    思路

    用户访问

    ==>

    mvc根据url找到controller/action

    ==>

    判断这个URL是否为库中定义的URL(排除非正常URL,PartialView产生的URL)

    ==>

    判断用户是否有这个URL的权限

    ==>

    正常访问

    层关系图

    实现

    使用了MVC环境下的AOP方法拦截技术,它主要通过过滤器(AuthorizeAttribute)来实现对action的拦截,然后注入自己的代码,这也是MVC几大过滤器带给我们的惊喜!

    AuthorizeAttribute 为我们提供了一个用户授权的过滤器,当用户访问Action之前,它将被执行

       // 摘要:
        //     表示一个特性,该特性用于限制调用方对操作方法的访问。
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
        public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
        {
            // 摘要:
            //     初始化 System.Web.Mvc.AuthorizeAttribute 类的新实例。
            public AuthorizeAttribute();
    
            // 摘要:
            //     获取或设置用户角色。
            //
            // 返回结果:
            //     用户角色。
            public string Roles { get; set; }
            //
            // 摘要:
            //     获取此特性的唯一标识符。
            //
            // 返回结果:
            //     此特性的唯一标识符。
            public override object TypeId { get; }
            //
            // 摘要:
            //     获取或设置授权用户。
            //
            // 返回结果:
            //     授权用户。
            public string Users { get; set; }
    
            // 摘要:
            //     重写时,提供一个入口点用于进行自定义授权检查。
            //
            // 参数:
            //   httpContext:
            //     HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。
            //
            // 返回结果:
            //     如果用户已经过授权,则为 true;否则为 false。
            //
            // 异常:
            //   System.ArgumentNullException:
            //     httpContext 参数为 null。
            protected virtual bool AuthorizeCore(HttpContextBase httpContext);
            //
            // 摘要:
            //     处理未能授权的 HTTP 请求。
            //
            // 参数:
            //   filterContext:
            //     封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。
            protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);
            //
            // 摘要:
            //     在过程请求授权时调用。
            //
            // 参数:
            //   filterContext:
            //     筛选器上下文,它封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。
            //
            // 异常:
            //   System.ArgumentNullException:
            //     filterContext 参数为 null。
            public virtual void OnAuthorization(AuthorizationContext filterContext);
            //
            // 摘要:
            //     在缓存模块请求授权时调用。
            //
            // 参数:
            //   httpContext:
            //     HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。
            //
            // 返回结果:
            //     对验证状态的引用。
            //
            // 异常:
            //   System.ArgumentNullException:
            //     httpContext 参数为 null。
            protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
        }

    对于我们的菜单权限过滤器,需要继承它,我们起名为ManagerUrlAttribute,下面是大叔设计的代码,大家可以作为参考

        /// <summary>
        /// 后台URL菜单的权限
        /// 需要考虑到PartialView的问题
        /// </summary>
        public class ManagerUrlAttribute : AuthorizeAttribute
        {
            /// <summary>
            /// 验证失败后所指向的控制器和action
            /// 可以在使用特性时为它进行赋值
            /// </summary>
            public ManagerUrlAttribute(string failControllerName = "Home", string failActionName = "Login")
            {
                _failControllerName = failControllerName;
                _failActionName = failActionName;
            }
            /// <summary>
            /// 出错时要跳转的控制器
            /// </summary>
            string _failControllerName;
            /// <summary>
            /// 出错时要跳转的action
            /// </summary>
            string _failActionName;
            /// <summary>
            /// 菜单仓储
            /// </summary>
            static IExtensionRepository<WebManageMenus> menuRepository = new ManagerEfRepository<WebManageMenus>(new ManagerContext());
            /// <summary>
            /// 所有已经定义的菜单项
            /// </summary>
            static List<WebManageMenus> allMenuList = menuRepository.GetModel().ToList();
    
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
    
                var menuIdArr = Array.ConvertAll<string, int>(CurrentUser.ExtInfo.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries), i => int.Parse(i));
                var menuUrlArr = allMenuList.Where(i => menuIdArr.Contains(i.Id)).Select(i => i.LinkUrl).ToList();
                var controllerName = filterContext.RouteData.Values["controller"].ToString();
                var actionName = filterContext.RouteData.Values["action"].ToString();
                var isValid = allMenuList.FirstOrDefault(i => i.LinkUrl == "/" + controllerName + "/" + actionName) != null;//是否为有效的URL,过滤分布视图
    
                //当前为正常页面,不是分布视图
                if (isValid)
                {
                    //没有当前URL的权限,跳到登陆页
                    if (!menuUrlArr.Contains("/" + controllerName + "/" + actionName))
                    {
                        filterContext.Result = new RedirectToRouteResult("Default", new RouteValueDictionary { 
                                  { "Action",_failActionName },
                                  { "Controller", _failControllerName} });
                    }
                }
            }
    
        }

    本代码解决了分布视图在过滤器中的尴尬,将分布视图产生的action进行过滤,我们先将所有定义的菜单URL取出来,然后用户访问时,先判断当前URL是否为已经定义的URL,如果是,再进行权限的比较.

     回到目录

  • 相关阅读:
    socket使用大全
    UIImageView控件使用(转)
    多线程,socket,http,asihttpRequest,等总结集合
    ios 如何判断字符串含有中文字符?
    修改UISearchBar
    abc222_e Red and Blue Tree(树上差分+01背包)
    2020icpc上海部分题解
    abc215_e Chain Contestant(状压dp)
    bzoj3238 差异(后缀数组+单调栈)
    NCD2019部分题解
  • 原文地址:https://www.cnblogs.com/lori/p/5660704.html
Copyright © 2020-2023  润新知