解耦的故事:权限设计

来源:百度文库 编辑:神马文学网 时间:2024/03/29 20:12:06
解耦的故事:权限设计
作者:小生 来源:博客园酷勤网收集 2008-06-13
摘要
酷勤网
要解耦﹐首先就要进行抽象﹐权限究竟能不能抽象?我认为通常意义上的权限应该分为2类﹕一类是用户是否有权进行某项动作﹐如管理员可以删贴﹐人事考勤员可以修改考勤数据。另一类我将它称为数据权限﹐如某某人可以查看某某部门的人员信息﹐某某人审核某某厂别的订单等
系统设计一个很重要的目的就是为了重用﹐而要做到重用﹐低耦合是最有效的手段。
本文将通过web应用系统中一个最常见的主题--权限设计﹐来说明解耦的应用。
要解耦﹐首先就要进行抽象﹐权限究竟能不能抽象?
我认为通常意义上的权限应该分为2类﹕
一类是用户是否有权进行某项动作﹐如管理员可以删贴﹐人事考勤员可以修改考勤数据。这种权限就是最简单的有或无问题﹐毫无疑问﹐这是可以抽象出来单独进行设计的。
另一类我将它称为数据权限﹐如某某人可以查看某某部门的人员信息﹐某某人审核某某厂别的订单﹐某某人具有某某报表的下载权限等﹐这种权限与具体的应用系统有关﹐与具体的应用逻辑有关﹐需要在系统分析时解决的﹐并在程序中嵌入这些代码﹐当业务逻辑发生改变时﹐常常需要修改这些代码逻辑。
当然这种权限应用也可以进行抽象﹐但是其耦合程度相对较高﹐抽象后进行的重用是在coding级别的﹐比如封装了权限的分配﹐移除和获取代码﹐但是需要new 一个权限类﹐并在业务系统中使用该权限类。
本文着重通过第一类权限的应用的说明来阐述解耦的应用.
第一类权限其实是应用最为广泛的权限﹐对此类权限设计最常见的就是分角色﹐如一个BBS﹐有管理员﹐斑竹﹐普通用户﹐匿名用户4种角色。每个人员是一种角色﹐每种角色可访问的菜单﹐页面或按钮是不一样的。
一些小型的﹐逻辑相对简单﹐应用已稳定的系统使用此种方法可大大减化权限的设计。
但是它毕竟是耦合的。
举个最简单的例子﹐例如在贴子列表页面上﹐斑竹可能在每个贴子后面会多一个删除按钮﹐而普通用户则不会有此按钮。程序员经常需要这样编码﹕
if(user is 管理员 或 斑竹)
删除按钮.visible = true
else
删除按钮.visible = false
乍看这样的代码﹐是看不到有什么问题的。但至少有一点ugly的就是出现了程序员最忌讳的HardCode代码:user is 管理员 或 斑竹﹐可能有人说这一点点不会有太大影响。
但是这至少让我们的系统有了如下的假定﹕
1﹕只有管理员或斑竹才能删除贴子﹐这种假设是很难站住脚的﹐系统不断变化﹐很容易哪天出现了一个"代斑竹"或"副斑竹"的角色﹐它们也可以删贴...
2﹕系统建立在这几种固定的角色之上﹐相信除了这个页面的判断角色代码外﹐系统的其它地方一定也会充斥这样的代码﹐一旦要改﹐那就只好将此类代码全部找出来...
一旦这些假设变化了﹐系统就会被这种耦合”拖累”
在我几年的程序设计生涯里﹐碰到的这种权限修改要求可谓数不胜数﹐某个主管打电话过来﹐能不能帮我开放一下考勤查询权限﹐我想看到我们部门的考勤状况。天啦﹐考勤查询是考勤员才能查的呀﹐开放这个给他可以呀﹐但更多的只有人事考勤员才能操作的功能都"不安全"的暴露在他面前了﹐谁知道它会不会去点点里面的哪个按钮?
你也许会说﹐当初开发程序时﹐需求分析就应该做清楚﹐现在请按正常的系统维护流程来做。
不单说他是主管﹐也可能是客户﹐我们就无法拒绝。
更重要最终我们还要是改程序﹐还是要面对哪些散落在系统各个角落的权限判断代码﹐为什么当初我们就不留下一个心眼呢?
解决的方法就是将权限抽象﹐与具体的业务系统解耦﹐开发系统的时候完全不去考虑这个系统有哪些角色﹐他们哪些人可以做什么﹐哪些人又可以做什么。而是将这部分需求撇开。
比如我们在编写删除贴子的代码时﹐就完全不用写下
if(has 删除权限)
//删除贴子代码
而是直接就写删除﹐我管你有没有删除权限﹐但你代码既然执行到了这里﹐那我假定你肯定就有删贴子的权限﹐至于你是管理员﹐斑竹﹐副斑竹﹐甚至是普通用户我也不管﹐也许你高兴﹐让某个普通用户也暂时可以删贴子(客户或主管要求嘛)
这样我们就把整个系统的功能全部开发出来了。
现在﹐任何人进入系统﹐映入它眼帘的就是所有菜单﹐所有按钮﹐太舒服了。
好了﹐现在我们再来考虑用户的权限要求吧﹕
用户要求分4种角色﹕管理员﹐斑竹﹐普通用户﹐匿名用户
管理员什么事情都可以做
斑竹只可以删贴
普通用户可以撤斑竹
匿名用户只能进入浏览页面
建几个表﹐做一下对应﹐然后写一个方法﹐传入userid和功能﹐返回true或false就可以了(我以前的贴子有介绍过一种具体的方案)。
这个权限管控放在哪里呢?
很简单﹐只要不要和你的业务代码放在一起就可以了﹐也许你可以通过AOP这种时髦的方式来完成﹐或者最简单的﹐就写一个类﹐在每次调用方法时﹐统一判断权限。
在web系统中就最简单了﹐只要做一个访问的url和功能的对应关系﹐然后利用一个httpmodule在每次request时﹐先把url转换成功能﹐然后再调用上述权限判断方法﹐返回true就进﹐false就转向错误页面。
可以看出﹐我们的应用系统很干净﹐我们的权限模块也很干净。
最后再提一下﹐在这种权限方案做web页面时经常碰到的一种情形﹐就是我刚刚提到的同一个页面可能有不同权限的情形﹐你无论如何都回避不了那行
if(user is 管理员 或 斑竹)
删除按钮.visible = true
else
删除按钮.visible = false
的代码。
是这样的
但是换过一个角度我们就能理解了﹐我们不把这种权限看作业务逻辑﹐我现在只是在提供功能﹐需要提供2种功能﹐浏览和管理﹐那好﹐我写两支程序。一支show.aspx﹐一支manage.aspx
别人会说你有病
确实有病﹐明明是差不多完全一样的代码﹐为什么要写两支程序﹐这不找抽吗?
没办法﹐我就写一支程序
postlist.aspx
但是两个功能的访问地址分别是﹕
post.aspx?type=show
post.aspx?type=manage
那行代码也巧妙地变为了﹕
if(request["type"]=="manage")
删除按钮.visible = true
else if(request["type"] == "show")
删除按钮.visible = false
这样你就看到了﹐程序员在写这个页面的代码时﹐完全占据了主动﹐再也不会去问系统分析师﹕老大﹐究竟谁才有删贴子的权限呢?
而只要对老大说﹐老大﹐你要的程序已经写好了﹐浏览和管理的页面分别是...
你爱怎么用就怎么用吧﹐什么? 权限? 管我什么事?
呵呵﹕)
就到这里﹐欢迎讨论。