十年磨一劍--從程序員到架構師

一个.net程序员,一个企业应用的开发者,喜欢系统架构,数据库,领域驱动,面向对象,表现层技术。关注重用的理论和实践。设计原则:简单,快速,适应变化能力强,表现层灵活多变...

博客园 首页 新随笔 联系 订阅 管理

系统设计一个很重要的目的就是为了重用﹐而要做到重用﹐低耦合是最有效的手段。

 

本文将通过web应用系统中一个最常见的主题--权限设计﹐来说明解耦的应用。

 

要解耦﹐首先就要进行抽象﹐权限究竟能不能抽象?

 

我认为通常意义上的权限应该分为2类﹕

一类是用户是否有权进行某项动作﹐如管理员可以删贴﹐人事考勤员可以修改考勤数据。这种权限就是最简单的有或无问题﹐毫无疑问﹐这是可以抽象出来单独进行设计的。

 

另一类我将它称为数据权限﹐如某某人可以查看某某部门的人员信息﹐某某人审核某某厂别的订单﹐某某人具有某某报表的下载权限等﹐这种权限与具体的应用系统有关﹐与具体的应用逻辑有关﹐需要在系统分析时解决的﹐并在程序中嵌入这些代码﹐当业务逻辑发生改变时﹐常常需要修改这些代码逻辑。

当然这种权限应用也可以进行抽象﹐但是其耦合程度相对较高﹐抽象后进行的重用是在coding级别的﹐比如封装了权限的分配﹐移除和获取代码﹐但是需要new 一个权限类﹐并在业务系统中使用该权限类。

 

本文着重通过第一类权限的应用的说明来阐述解耦的应用.

第一类权限其实是应用最为广泛的权限﹐对此类权限设计最常见的就是分角色如一个BBS﹐有管理员﹐斑竹﹐普通用户﹐匿名用户4种角色。每个人员是一种角色﹐每种角色可访问的菜单﹐页面或按钮是不一样的。

一些小型的﹐逻辑相对简单﹐应用已稳定的系统使用此种方法可大大减化权限的设计。

 

但是它毕竟是耦合的。

 

举个最简单的例子﹐例如在贴子列表页面上﹐斑竹可能在每个贴子后面会多一个删除按钮﹐而普通用户则不会有此按钮。程序员经常需要这样编码﹕

if(user is 管理员 斑竹)

    删除按钮.visible = true

else

    删除按钮.visible = false

 

乍看这样的代码﹐是看不到有什么问题的。但至少有一点ugly的就是出现了程序员最忌讳的HardCode代码:user is 管理员 斑竹﹐可能有人说这一点点不会有太大影响。

 

但是这至少让我们的系统有了如下的假定﹕

1﹕只有管理员或斑竹才能删除贴子﹐这种假设是很难站住脚的﹐系统不断变化﹐很容易哪天出现了一个"代斑竹""副斑竹"的角色﹐它们也可以删贴...

2﹕系统建立在这几种固定的角色之上﹐相信除了这个页面的判断角色代码外﹐系统的其它地方一定也会充斥这样的代码﹐一旦要改﹐那就只好将此类代码全部找出来...

 

一旦这些假设变化了﹐系统就会被这种耦合拖累

在我几年的程序设计生涯里﹐碰到的这种权限修改要求可谓数不胜数﹐某个主管打电话过来﹐能不能帮我开放一下考勤查询权限﹐我想看到我们部门的考勤状况。天啦﹐考勤查询是考勤员才能查的呀﹐开放这个给他可以呀﹐但更多的只有人事考勤员才能操作的功能都"不安全"的暴露在他面前了﹐谁知道它会不会去点点里面的哪个按钮?

 

你也许会说﹐当初开发程序时﹐需求分析就应该做清楚﹐现在请按正常的系统维护流程来做。

 

不单说他是主管﹐也可能是客户﹐我们就无法拒绝。

更重要最终我们还要是改程序﹐还是要面对哪些散落在系统各个角落的权限判断代码﹐为什么当初我们就不留下一个心眼呢?

 

解决的方法就是将权限抽象﹐与具体的业务系统解耦﹐开发系统的时候完全不去考虑这个系统有哪些角色﹐他们哪些人可以做什么﹐哪些人又可以做什么。而是将这部分需求撇开。

比如我们在编写删除贴子的代码时﹐就完全不用写下

if(has 删除权限)

   //删除贴子代码

 

而是直接就写删除﹐我管你有没有删除权限﹐但你代码既然执行到了这里﹐那我假定你肯定就有删贴子的权限﹐至于你是管理员﹐斑竹﹐副斑竹﹐甚至是普通用户我也不管﹐也许你高兴﹐让某个普通用户也暂时可以删贴子(客户或主管要求嘛)

 

这样我们就把整个系统的功能全部开发出来了。

 

现在﹐任何人进入系统﹐映入它眼帘的就是所有菜单﹐所有按钮﹐太舒服了。

 

好了﹐现在我们再来考虑用户的权限要求吧﹕

用户要求分4种角色﹕管理员﹐斑竹﹐普通用户﹐匿名用户

管理员什么事情都可以做

斑竹只可以删贴

普通用户可以撤斑竹

匿名用户只能进入浏览页面

 

建几个表﹐做一下对应﹐然后写一个方法﹐传入userid和功能﹐返回truefalse就可以了(我以前的贴子有介绍过一种具体的方案)

 

这个权限管控放在哪里呢?

很简单﹐只要不要和你的业务代码放在一起就可以了﹐也许你可以通过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

 

这样你就看到了﹐程序员在写这个页面的代码时﹐完全占据了主动﹐再也不会去问系统分析师﹕老大﹐究竟谁才有删贴子的权限呢?

 

而只要对老大说﹐老大﹐你要的程序已经写好了﹐浏览和管理的页面分别是...

你爱怎么用就怎么用吧﹐什么? 权限? 管我什么事?

 

呵呵﹕)

 

就到这里﹐欢迎讨论。

 

posted on 2008-05-29 15:50  Kevin Zou  阅读(7705)  评论(31编辑  收藏  举报