`

来谈谈REST、RBAC下的URL权限控制

阅读更多
    从几个月前开始接触REST,到现在尝试去设计、开发一个RESTful的web应用。说实话,到目前为止我还对REST理解的很浅很浅。今天偶尔又去翻了翻互动百科对REST的描述,感觉那位网友写的真好,但是有些观点我还是有不同的意见。
互动百科上关于REST的页面:http://www.hudong.com/wiki/REST

1.上面比较后面的一句话里说到:如果我们可以把所有的用户需求都可以抽象为资源,那么MVC就可以退出历史的舞台了。如果情况相反,那么我们就需要混合使用REST和MVC。

    我个人看到这句话后,立马觉得不可思议,什么时候MVC和资源杠上了?甚至到达了非彼即此的地步!MVC仅仅是一种分层结构而已,它只是隔离了用户界面和真正的业务逻辑代码,然后靠控制器来连接这两者,在这个分层里,完全没有涉及到资源哇,注意我这里说”涉及“,并不是说MVC中不可能出现资源的概念。所以我很有疑问,假设用户需求(web应用里,用户需求=http请求响应)都能抽象成资源,那么MVC就可以退出历史的舞台了,这句话说的太过了,资源和MVC根本就不是对立的。在REST中,资源被URL标识,用户依靠url来发出请求,请求到达服务器,服务器提供相应的url处理并响应,这个过程你可以设计成MVC模式的,也可以设计成最恶心的页面写代码的模式,例如你完全可以将url直接发到某个jsp上面嘛。然后逻辑代码全都写在页面上。你敢说这不是RESTful的嘛?在MVC Model1的年代里,JSP页面既充当控制器,又充当视图,JavaBean封装业务逻辑,在那个架构中,也完全可以RESTful。所以这两者完全不是非彼即此的关系。

2.REST的核心问题是如何抽象资源。

    关于这点我表示很赞成。资源是一个很抽象的东东。极端点的,可以认为任何能够被标识的东东都能被抽象成资源。说到这里,我其实很想谈谈在我前一篇文章里有个朋友问到”分页权限控制“问题,说基于RBAC的权限控制很难、甚至无法对分页适用。详情看http://www.iteye.com/topic/1112793二楼,当时我也一下子表示不太明白。现在回头想想,其实RBAC的权限控制本身是适合的,关键问题是,他们在解决分页权限这种涉及到数据级别的权限控制问题上,总是想用sql语句来解决它!

    我尝试假想一下下面这种场景:
    实体:新闻(id,分类,标题,内容,作者)
    实体:分类(id,名称)
    实体关系:新闻(多)—>分类(一)
    REST:
    用户需求                     url设计
    分页查看所有新闻             news/index/{pageNum} GET
    分页查看某类新闻             news/{cate}/index/{pageNum} GET
    查看某篇新闻                 news/{id} GET
    查询所有新闻且是分页的       news/search/{keyword}/{pageNum} GET
    发表新闻                     news POST
    删除新闻                     news/{id} DELETE
    修改新闻                     news/{id} PUT

    这里我可能比较极端,尽力在避免url含有?后面的参数,因为http的url是?前面部分。既然要用url唯一标识资源,那么肯定不能靠两个相同的url,不同的?参数来标识,因为在http中(至少在tomcat)中,这两者是一样的。除非你自己实现一个判断url+?后面参数来保证url的唯一性,但是http方法中的POST、GET、PUT、DELETE却可以。虽然后两者浏览器不支持,但是http协议包含。

    回到前面的场景,上次在我那帖子里,那位朋友说到分页权限控制问题。在这里我利用上面的场景,模拟一下他说的情况,当然不一定理解到他的意思。

    现在有一个新的需求:在后台登陆用户中,信息发布员角色的用户只能查看作者为自己的新闻。

    问题来了:在我们前面设计的url中,分页查看某类新闻或者分页查看所有新闻中都没有关于新闻作者的权限控制。那么,这时候我们该怎么办?

    好多人可能会:在代码里保证(sql语句里),尽力满足新的需求,但是这样问题更多了,这时候权限控制就麻烦了,因为此时很明显的基于url的权限控制模型无效了!因为这时候你不是靠url来控制权限,而是通过sql语句了。

    我个人是非常不赞同这种做法的,这种做法很恶心,虽然交给sql语句来做看起来不错。嗯,是的,我并不反对通过sql语句来辅助,但是我反对通过sql语句来控制权限。注意这里我强调的是”sql语句控制权限“。在我的那篇文章里似乎表达的应该是基于url来控制。因为在我看来,确实web应用系统里所有的需求都能被抽象成资源,用url来标识。

    关键点出来了,需求——>抽象——>资源<——URL标识。

    那么,上面新的需求是:在后台登陆用户中,信息发布员角色的用户只能查看作者为自己的新闻。下面我们的任务将是如何来把这个需求抽象成资源,而不是想法设法的去动其他需求里写好的代码。
  
    我个人会这么做:该新的需求中影响到了它的另外几个需求,把被影响的两个url的权限从信息发布员用户权限中去除。新定义两个url,分配给该用户。具体做法是:

    角色为信息发布员的用户:
    分页查看所有新闻 news/index/{pageNum}  GET 删除该角色用户的访问权限
    分页查看某类新闻 news/{cate}/index/{pageNum} GET 同上
    查询所有新闻且是分页的 news/search/{keyword}/{pageNum} GET 同上
    为该角色新添加符合它需求的url,然后分配权限给该角色。下面仅举一个例子:
    分页查看所有作者为当前用户的新闻 news/index/{pageNum}/{author}

    在这个url映射到的action处理方法中,该怎么写就怎么写,无需去管权限的问题,也就是说,在action代码中,不要尝试的去比较传过来的author的值和session用户中的值。因为我的url权限控制模型已经帮你做了。至于具体如何做,这里暂时不想谈,但是可以说说原理,1.拦截器(是对每次action访问的拦截,且在拦截器中能够根据当前拦截到的url,找到绑定到它的url参数适配器,例如对于{author}参数的适配器,在该适配器中,大概思路是获取author,然后跟当前session中的用户作者比较,如果不同,就输出权限不够的信息。否则,chain一下就完事了。当然,适配器肯定是支持用户自己扩展的。)

    稍微补充点:我的url权限控制模型,url是支持变量的,例如news/index/{pageNum},这个url在真正进入角色权限表时,是会被转成正则表达式news/index/\d+,分配给某角色之后,该角色访问所有news/index/数字都会被通过。另外,该模型还能够在定义url的时候,允许自己实现对url动态参数的赋值。例如news/index/{pageNum}可以给它绑定一个参数适配器,在该适配器中,可以给定值给pageNum,告诉模型,该值只能是什么,例如只能是1,2,3等,甚至可以是是session中的值,总之,该模型本质上是一个拦截器,能够获取reqeust,response,out,session等重要的环境对象。

    最后总结下:其实基于RBAC下的url权限控制模型是可靠的,一般而言,需要权限控制的数据都在访问url中能够获取,那么对于数据库字段或者行级别的权限验证,是能够通过url参数适配器的方式去实现的。而且整个url权限控制模型又符合RESTful。
   
    自家之言,欢迎拍砖。PS:暂时还在晚上我的这个url权限控制模型中。但是思路总体来说就是上面所讲。

谢谢阅读。
分享到:
评论
6 楼 czqjay 2016-07-21  
news/index/{pageNum}/{author}

{author}  不传, 你看看会发生什么?
5 楼 yangkun311 2013-01-29  
很明显~~REST的无状态~~所以这种也是错误的~
4 楼 liuxiang00435057 2012-10-16  
兄弟能加我QQ124180505,跟你学习下
3 楼 swanky_yao 2012-07-09  
值得一试 不过可能还有很多细节问题
2 楼 KingCobra 2012-07-06  
REST架构一个重要的准则就是无状态性,这个你忽略了吧。
1 楼 mmtzwyd 2012-05-18  
可否将鉴权过程与rest的服务给剥离开呢?

相关推荐

Global site tag (gtag.js) - Google Analytics