• 老话题,权限设计及实现!


    前言

      以前也写过两篇关于权限这个话题的文章《我所理解的权限》《Asp.net Mvc 身份验证、异常处理、权限验证(拦截器)》,最近在新的项目中,权限设计这块做了重新的考虑和设计。一直有人说权限这个东西不能太死,所以我们本着把权限尽量做到透明化,而设计了这样的权限管理。

    设计思路

    1、因为项目使用的是asp.net mvc,在mvc中一个action就对应的是一个URL,一般来说一个action只会做一件事情,所以我们获取请求的action就可以知道你将要干什么,那么我们把系统中所有的模块全部存放到数据库中,并且把功能按钮也放到数据库中,可以构造成一个树形菜单的形式。如图:

    其中,这里分为导航权限和功能权限,导航权限指:系统运行时会自动根据权限分配加载到导航树上去的;功能权限指:这个页面上有哪些按钮。这里我采用一个标识来区分哪些为导航权限,哪些为功能权限。因为登录系统,加载导航栏时只需要获取导航权限进行验证就OK了。

    2、保存用户权限,在角色赋权的页面,直接加载整个导航表中的数据,采用树形展示,在角色表中保存模块表的主键ID即可。

    3、为角色关联用户则可以直接关联用户的ID或者工号什么的都可以。

    4、拉取权限加载导航,用户登录即可去角色表中获取到该用户拥有哪些角色。获取模块表ID,根据模块表ID,获取模块表数据,剔除功能权限,然后动态加载导航。

    5、功能权限的验证方案,这也是考虑很久的一个地方,以前的思路就是直接传一个参数值去判断是否显示这个按钮。这次采用了对HTML进行剔除的方式进行功能按钮的隐藏和显示。

    具体实现

    1、导航权限验证:采用拦截器,在action执行前进行权限验证。

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //当前访问地址
        string Code = string.Format("/{0}/{1}", filterContext.RouteData.Values["controller"].ToString(), filterContext.RouteData.Values["action"].ToString()).ToLower();
        string[] ListResource = ResourceBiz.Instance.Get(new string[] { "Url" }).Select(p => p.Url).Where(p => !string.IsNullOrEmpty(p)).Select(p => p.ToLower()).ToArray();//获取模块表导航代码这个字段与当前URL比对
        if (!ListResource.Contains(Code))//模块表中不存在的URL,默认不进行验证
            return;
        if (!Authentication.GetResourceCode().Contains(Code))//Authentication.GetResourceCode()为当前用户所拥有的权限
        {
            //验证不通过
            ContentResult Content = new ContentResult();
            Content.Content = "<script type='text/javascript'>alert('权限验证不通过!');history.go(-1);</script>";
            filterContext.Result = Content;
        } 
    }

    2、验证页面的功能权限:也是采用拦截器,在action执行后,获取即将渲染的HTML源码进行分析及剔除操作。

    //获取即将呈现的HTML,剔除功能按钮
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {//用户控件则不进行筛选
       if (!filterContext.IsChildAction)
          filterContext.HttpContext.Response.Filter = new WhitespaceFilter(filterContext.HttpContext.Response, filterContext);//重写
    }
    //重写
    public class WhitespaceFilter : System.IO.MemoryStream
    {
        private System.IO.Stream Filter = null;
        private ResultExecutedContext filterContext = null;
        private string Source = string.Empty;
    
        //构造函数,用来接收变量
        public WhitespaceFilter(HttpResponseBase HttpResponseBase, ResultExecutedContext filterContexts)
        {
            Filter = HttpResponseBase.Filter;
            filterContext = filterContexts;
        }
        //读取HTML源码
        public override void Write(byte[] buffer, int offset, int count)
        {
            Source += System.Text.Encoding.UTF8.GetString(buffer);//HTML源码  
        }
        //分析进行权限处理
        public override void Close()
        {
            //当前访问地址
            string Code = string.Format("/{0}/{1}", filterContext.RouteData.Values["controller"].ToString(), filterContext.RouteData.Values["action"].ToString()).ToLower();
            string[] ListResource = ResourceBiz.Instance.Get(new string[] { "Url" }).Select(p => p.Url).Where(p => !string.IsNullOrEmpty(p)).Select(p => p.ToLower()).ToArray();//获取模块表所有记录
            if (ListResource.Contains(Code))//模块表中不存在的URL,默认不进行验证
            { //解析处理
                HtmlDocument Document = new HtmlDocument();
                Document.LoadHtml(Source);
                HtmlNode htmlNode = Document.DocumentNode;

           /*这里需要获取这个模块下所有的共功能权限,然后跟你所拥有的这个页面的功能权限比对,如果不拥有这个功能权限,则可以根据规则获取到这段HTML,然后删除掉*/
    /*_______________________开始分析处理功能按钮,这里可以自己增加验证规则___________________________*/ HtmlNodeCollection hnc = htmlNode.SelectNodes("//a");//获取需要验证的功能按钮HTML,由开发人员自己定义,你也可以给个特定的标识来标识这个标签为功能按钮,譬如:htmlNode.SelectNodes("//a[@class='add']");获取神马的 if (hnc != null) { foreach (HtmlNode node in hnc) { //拿到所有A标签,然后把href取出来,跟当前用户所拥有的功能权限比对,如果相等或者包含则删除 string CodeStr = node.Attributes["href"] != null ? node.Attributes["href"].Value.ToLower() : ""; node.ParentNode.RemoveAll(); } } } Filter.Write(System.Text.Encoding.UTF8.GetBytes(Source), 0, System.Text.Encoding.UTF8.GetByteCount(Source)); base.Close(); } }

    这样设计的话,系统中关于权限的地方就全部透明化了。只是在功能权限验证时,要把所有情况全部考虑进去,不知道从文字中大家能不能明白我所需要表达的意思,文笔实在太差了。

    作者:LyIng.Net
    出处:http://www.cnblogs.com/jiangbiao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    第二章 算法基础 思考题2-4(逆序对)
    JSF中使用f:ajax标签无刷新页面改变数据
    JSF在ui:include中传递参数到对应控制层
    JSF通过超链接传递参数到控制层
    给JavaScript文件传入参数的几种方法
    Spring 与 @Resource注解
    GWT嵌入纯HTML页面
    一个分类,两个问题之ArrayList
    GWT更改元素样式属性
    Hello 2019 D 素因子贡献法计算期望 + 概率dp + 滚动数组
  • 原文地址:https://www.cnblogs.com/jiangbiao/p/2799803.html
Copyright © 2020-2023  润新知