转载:闲话权限设计三层境界

转自:

http://www.cnblogs.com/tsoukw/archive/2010/09/27/1836485.html

 

喜欢金庸的武侠,对他那几部小说也是乐此不疲


拿独孤求败来说,他的剑,从无名利剑,玄铁重剑,到木剑乃至最后的无剑,不知道破世间多少玄机


软件设计与用剑也颇有几分相似之处



下面就拿大家耳熟能详的权限设计为例,聊聊我对权限设计理解的三个层次吧


第一层:手中有剑,心中无剑


年少时,凭着手上的这把无名利剑,锋芒毕露,以为只要有这件利器在手,这天下便唯我独尊。



"XX,你那个薪资查询系统,怎么谁都可以进去查啊?"


"啊?..."


"只有总经理和他的助理可以查!"


"哦..."


if(Session["UserID"]==null)


        throw new PermissionException("必须登录");


string userID = Session["UserID"].ToString();


if(!(userID=="88.00" || userID=="888.00"))   //总经理的用户ID 88,总经理的助理用户ID:888


         throw new PermissionException("您没有访问此页的权限");


权限这玩意刚开始其实非常简单,谁又能不会?



然后听说大部分页面都要管控,很快:


public class PermissionHelper


{


     public static bool CheckPermission(string pageID);


}


用一个方法统一封装那部分代码。


再建一个table,记入哪些页面可以给哪些user访问


pageID  userID


-------   --------


薪资查询 88.00


薪资查询 888.00


薪资输入 99.00     --人事主管


----------------------------------


这样只要在PageLoad中CheckPermission一下就行



接着,又可以由要进行权限管控的页面统一继承一个类,然后只在这基类中call一次CheckPermission就行


public class PermissionPage:System.Web.UI.Page{


     override PageLoad(){


          PermissionHelper.CheckPermission(pageID);


      }


      protected abstract string pageID{get;}


}


权限页面继承此类,override pageID,就能完成当前页的权限管控



当然在asp.net中还有其它的一些方法,如利用asp.net的HttpModule,可以在访问页面之前就完成权限管控,这种方法耦合性更低,灵活性更高,不过可能就要多费一些功夫记录一下Request的Url和PageID对应才可


url    pageID


------------------


SalaryQuery.aspx   薪资查询


SalaryEdit.aspx   薪资输入


------------------------------------



昨夜西风凋碧树。独上高楼,望尽天涯路


执着,加上勤奋,终于利剑出鞘,手到擒来



当然,世间万物,各有不同


有通过控制WebForm的各种控件的状态(如Button的Enable,Visible)来控制权限的


也有在MVC中,通过在Controller中设定Attribute完成


还有控制菜单


控制数据库中table的栏位以及增/删/改/查的


可谓八仙过海,各显神通,最终都在自己的势力范围下建功立业



剑,是好剑,也能杀人


不过却不明白这把剑好在哪?


于是就今天用的还是青龙剑,明天却又发现了偃月刀也很犀利,可能也就转成刀客了


停留在此种境界,即是心中无剑,最终也不过是个剑客罢了



要做剑圣,还必须真正地研究各种不同的剑,领悟剑的本质,锻造出适合自己风格的绝世好剑--玄铁重剑


这也是第二层境界:手中有剑,心中也有剑



心中有剑后,手中的剑才能直指目标,更犀利,更直接,杀人于无形,真正雄霸天下。


要到这一层,除了要有“为伊消得人憔悴,衣带渐宽终不悔”的勇气和毅力,


还要悟



权限是什么


无非就是要让没有权限的人不能访问没有授权的物


那谁有权,谁没权


这就是权限的表示问题


不管是01也好,Table记录也罢,文件配置也行


最终都要告诉


人--物的对应,只能在有了这种对应之后,我们的权限管控才是物有所托。



当然,很多时候这两者不是直接对应的,


为了某种原因,如更易管理,更易写程式,更易提供界面等等,往往会设计一些中间过程


如人会加到群组里面,由群组来对应物


物也可以组成群组


但是不管中间多少层,最终还是人与物的对应。


最终要提供类似


HasPermission(UserID,ResourceID)(有无权限),


PermissionResource(UserID)(用户权限资源),


PermissionUser(ResourceID)(拥有资源权限的用户)等方法。



有了权限的表示,并不能阻止访问没有授权的资源,它只是一个死物,需要有地方去用它。


这就是权限的管控,它包括


1.选择管控的地点,即在哪里下手,在哪里进行管控


有通过PageLoad,有通过HttpModule,还有通过AOP在方法调用前横切管控等等


如果是资源权限,则可能在资源下拉框中按权限筛选,在提交时根据参数判断资源权限等等。


最终只要你记得,这是管控的地点


如何在系统中更简单,更方便地管控,取决于系统架构,其灵活性也让管控地点的选择是否顺利与简单



2.管控过程,分为四步


a.识别出人


cookie,Session,或者是c/s中的UserID变量,也可以是webservice的soap头经过登录后的用户ID,还可以是IP或者手机号码,最终都转为权限表示中的UserID


b.识别出物


Url,参数中的变量都行,最终要转成权限表示中的ObjectID


c.调用HasPermission(人,物)判断权限


这是由权限表示决定的方法


d.实施管控策略


对于无权限者,或转向无权登录页,或抛出异常,或Button.Visible = false最终实现权限管控



经过这个本质的识别,接下来就可以来锻造真正的玄铁重剑了


针对权限表示,设计一个比较通用的方案


也就是基本上能够通用的最简单抽象


---------------------------------


不吐不快,插播一下


在系统架构过程中,如何快速实现可供用户测试和使用的系统才是最重要的,至于一些底层服务框架,如数据访问,AOP横切,IOC,日志等,并不是越完美越好,而是要简单,要在自己全部理解的基础上使用,有了这个基础,就算碰到不能实现某些需求时,也可以很容易地通过自己修改去实现


就说日志吧,对于一些新手来说,完全没必要去用log4net,直接几行代码使用txt就完成日志记录了,要不然在程式出错时,除了要找寻程式为啥出错,还可能要去找为什么没有日志出来


还有如AOP,先想想整体架构,为什么需要AOP,AOP何时使用,如果使用spring.net,caslte,就会出现只要一个轮子,结果将整个汽车仓库都搬来了,不是不好,而是用不到,用不到再好的东西也等于零,关键是对于不熟悉的人,一旦出现问题,那维护起来也是相当麻烦


当然以上只是适用于不太熟悉的人,如果你对Castle或者log4net熟悉得就像老婆身上有哪几颗痣,在什么地方都知道,则另当别论


好了,拉回来,不跑远了


--------------------------------------


1:Object,Group的对应


2:User,Group的对应


基本上这个简单的抽象,就可以完成绝大部分权限表示问题(如果真有幸,碰到了剩下5%不能完成的权限表示时,那就再去抽象一次,最终提供权限表示上的权限方法就是)


对于权限方法,也只需写一遍,就可以用在任何权限类别上了


复制几个权限配置的片段吧


Ajax的权限


--------------------------


Role,Object


--------------------------
Admin,*


?,PCIWeb.ProgramsHelper.Programs


?,ClientTool.*


?,WebFileBrowser_CIFiles.*
?,WebFileBrowser_PQM.*
?,WebFileBrowser_ISO.*


?,MRB.BookingService.RoomBooking
?,MRB.BookingService.RoomBookingAfterNow
*,MRB.BookingService.Cancel
*,MRB.BookingService.Booking


--PQM系統
PQM_Exced,PQM.ExcedService.*
--7S,Lean,Kaizen
PQM_CI,PQM.CI



这是直接访问DB服务的权限


--------------------------


Role,Object


--------------------------
Admin,*


?,MRB/Room_Query
?,MRB/Borrow_Query2


--任何人都可以查詢每日超標回饋表
?,PQM/Exced_Query
?,PQM/Excem_Query
?,PQM/Excedd_Query
?,PQM/Excem_Query2



这是User与Role的对应


------------------------------


User,Role


------------------------------
850.00,Admin


850.00,PQM_Exced
206.00,PQM_Exced


54.00,Admin
54.00,PQM_Exced



其次,对于管控地点,不同的人的系统架构不同,可能实现也不一样。


笔者的系统架构采用RIA架构 + SOA服务,


因此在服务层使用aop的横切方式,就完成了服务权限的管控


而数据权限,也是抽象了几个UI控件,通过PermissionResource方法过滤下拉列表框和弹出Grid,而在服务调用时,在具体的程式中直接调用HasPermission方法进行管控



融入剑本质的玄铁重剑出炉,所向披靡


这把剑与当初那把无名利剑表面上似乎没有什么不同,但他的锻造过程更标准,剑招也需要内力的支撑。


举个例子来说,


通过URL管控,可能只能用于Web


而通过管控Button的Visible,虽然能管控到WinForm,但是WebService的权限怎么办


而明确了权限的本质后,针对各种不同的部分统一或单独实现,做到有的放矢,不再盲目跟从。


特别是如果自己的系统针对某一范围,更能够实现一套符合自己的通用的权限架构。



有了这一层的实现后,第三层的境界其实也是水到渠成,这便是


手中无剑,心中有剑


剑终究有形,不管它多轻,又或多通用,到处带着,始终会很累


只要心中有剑,就是手上拿着的是木剑也能杀人。



笔者所服务的部门留有很多旧系统,里面各种权限实现五花八门,加上移植兄弟公司的系统,里面也有单独的权限实现,对这一部分,原来还想全部改写,后来终于放下。


只要实现目的,管他什么手段


只是与刚开始的漫无目的不同,这时候已能十分清楚这些额外的权限是如何实现,有无漏洞等等


驾驭起来,也是顺风顺水



其实mvc的controller管控也非常不错,没有谁在这里做了漏网之鱼


其实webform的control管控也运行稳定,至今顺利在跑



存在即合理


为什么要去改变他们,为什么要花这么大心思去补救,去重构


生命中要做的事情太多太多 ,比权限管控更重要的事情也多得多,如何让用户查起来更顺手,如何让资料显示得更舒服,如何让画面更流畅。。。


资源管控住了就行,管它用什么方法,合适的就是最好的。


如一个webservice


系统总共就这么一个webservice


只允许本机访问(同一台主机,不同系统的数据交换)


那就在方法中直接写


if(HttpContext.Current.Request.UserHostAddress!="127.0.0.1")


    throw new PermissionException("抱歉,你没有访问这个web服务的权限");


这其中不也包括了


权限表示:hardcode在代码中,就是用户为127.0.0.1才有权限


管理地点:执行方法的主体代码前


识别人: HttpContext.Current.Request.UserHostAddress


识别物:就是当前管控的方法调用(在这里是隐式的)


调用权限表示方法验证:HttpContext.Current.Request.UserHostAddress!="127.0.0.1"


无权时的动作:throw new PermissionException("抱歉,你没有访问这个web服务的权限")


同样它就是一个标准的权限管控方案



信手拈来即是剑


按照权限思路,查看是否有漏洞,有则补之,无则放行


无剑一身轻



众里寻她千百度,蓦然回首,那人却在灯火阑珊处

转载于:https://www.cnblogs.com/yangfan/archive/2011/10/26/2225753.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361919.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webpack联邦模块之remotes方法

使用联邦模块后当前项目就会有两个依赖,一个是依赖共享模块,一个是依赖远程模块。运行时webpack/runtime/consumes用于解析共享模块,运行时webpack/runtime/remotes 用于解析远程模块。这两个模块对应的方法分别是__webpack_require__.f.cons…

径向菜单的制作

最终效果: 在径向菜单的制作前,首先需要知道几点知识点: Math.sin(x) x 的正玄值。返回值在 -1.0 到 1.0 之间; Math.cos(x) x 的余弦值。返回的是 -1.0 到 1.0 之间的数; 这两个函数中的X 都是指的“弧度”…

吉首大学2019年程序设计竞赛-F 天花乱坠

题目链接:https://ac.nowcoder.com/acm/contest/992/F 题意:给定正n边形,边长为100,以每条边的中点连线构成新的正n边形,无限循环下去,求所有边的长度和。 思路:简单数学计算题,可以…

SqliteHelper整理

刚开通博客不久,还没有发过文。这是第一篇,要鼓励我自己再接再厉。 另外,我也是刚刚踏上程序员这条路,有赖各位多多提携! 闲话不多说,最近参与的项目包含本地化存储这一块。昨天就园子里找了些资料有另外补…

webpack联邦模块之consumes方法

对于使用联邦模块的项目会有两个依赖,一个是远程模块,一个是共享模块。上一篇文章解释了远程模块的加载和安装并初始化共享作用域。consumes则是共享模块的解决方案,用于在运行时加载并安装依赖的共享模块。 为什么叫consumes?我…

vue-cli使用说明

一、安装npm install -g vue-cli 推荐使用国内镜像 先设置cnpm npm install -g cnpm --registryhttps://registry.npm.taobao.org 如果安装失败,可以使用 npm cache clean 清理缓存,然后再重新安装 然后使用 cnpm 安装 vue-cli 和 webpack cnpm inst…

OptaPlanner –具有真实道路距离的车辆路线

在现实世界中,车辆路径问题(VRP)中的车辆必须走这条路:它们不能在客户之间直线行驶。 大多数VRP研究论文和演示都乐于忽略此实现细节。 和我一样,过去。 尽管使用道路距离(而不是空中距离)不会对…

自旋锁

什么是自旋锁? 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 …

关于如何在PSA众多请求号中查找数据是属于哪一条。

其中有两个TCODE: RSTSODS与RSTSODS,我们可以查找数据源的PSA表,然后在SE16中可以看到。 另外我们对PSA点击管理,一般会出现在窗口上面出现PSA的表名。 当然有些不在的话,那就去查找那两个TCODE。转载于:https://www.cnblogs.com/…

TCP握手为什么需要三次通信

TCP三步握手three way (or three message) handshake 是TCP核心知识点,很长一段时间内我无法理解为什么TCP建立连接需要三次通信,而不是两次或者四次或者更多次。我翻了很多问答和博客,他们说的都很有道理,但是借来的火&#xff0…

小程序用户拒绝授权解决方法

众所周知,小程序进入首先都要进行微信授权的,那万一用户不小心点了拒绝按钮怎么办呢?不要慌,官方早已预料到此情况,并提供了api供开发者使用,下面就一起来研究下api吧 一、API接口 wx.openSetting(OBJECT)…

揭示垃圾收集暂停的时间长度

有几种方法可以改善您的产品。 一种方法是仔细跟踪用户的体验并在此基础上进行改进。 我们确实自己应用了此技术,并再次花了一些时间查看不同的数据 除了我们追求的许多其他方面之外,我们还提出了一个问题“延迟GC触发应用程序的最坏情况是什么”。 为了…

异步导致UI句柄增加的解决办法

在很多操作中,都会使用到异步线程,具体怎样使用在这不说了,网上有很好的说明;本人通过Delegate.BeginInvoke实现异步调用,完成后对UI控件进行设值等,还有System.Timers.Timer都一样,使用的是线程…

[转]android ListView详解

本文转自:http://www.cnblogs.com/allin/archive/2010/05/11/1732200.html 由于google doc 很多人都打不开,故更新了源码下载地址 【源码下载】----2011-01-18 在android开发中ListView是比较常用的组件,它以列表的形式展示具体内容&#xff…

JS对象操作

一、String常用操作 1.截取 substr(start,length) //返回从指定位置开始的指定长度的字符串。 substring(start,end) //返回两个指定的位置之间的字符串。 slice(start,end) //包括字符串 stringObject 从 start 开始(包括 start)到 end 结束&#xff0…

JBoss BPM Suite 6.0.3版本的5个实用技巧

上周,红帽发布了标记为6.0.3的JBoss BPM Suite的下一版本,已订阅的用户可以在其客户门户中使用。 如果您对该版本的新增功能感到好奇,请在客户门户网站上在线查看版本说明和其余文档 。 我们正在寻找一些简单的方法来开始使用此新版本&…

package-lock.json

package.json确定依赖的范围,package-lock.json将这个范围精确到具体版本。主要是为了解决在各个环境中得到确定的node_modules,如果只依赖package.json因为该文件声明的是直接依赖的范围,它无法将直接依赖固定在某个特定版本,也无…

Linux启动管理

启动管理系统运行级别 运行级别:含义0 :关机1 :但用户模式,可以想象为windows的安全模式,主要用于系统修复2 :不完全的命令行模式,不含NFS服务3 :完全的命令行模式,就是标…

VB网站收集

1.vb源码 http://hi.baidu.com/aboutvb/home转载于:https://www.cnblogs.com/sode/archive/2011/11/05/2236883.html

Django学习---原生ajax

Ajax 原生ajax Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)。 XmlHttpRequest对象的主要方法: a. void open(String …