词条统计
浏览次数:7366 次
编辑次数:1次 历史版本
最近更新:2013/6/20
创建者:掷鸡蛋者


对于检查权限的工作,我们分成两部分:

1、权限系统如何设置?(即建立怎样的权限模型?)
2、如何将权限模型落实到代码中?(也就是检查的代码插入到系统的哪个位置?)

下面就分成这两部分解释一下:

一、权限系统如何设置

最常见的设置方式,是基于角色的访问控制RBAC(Role-Based policies Access Control)方式。一般涉及如下领域模型:

a)用户(User)
b)角色(Role)
c)许可(Permission)

一个用户可以拥有多个角色,某个角色对应着多种许可。
给用户分配权限,就是给用户分配角色。同时,系统管理员可以在后台设置某种角色对应的许可。
注意,用户不直接和许可发生关联。
用户登录系统之后,通过检查用户具有的所有角色,获取用户具有的所有许可,最后判断出是否具备当前操作的权限。

这种权限模型还可以进一步细化,比如抽象出资源(Resource);比如对角色进行分组、分级……在较为复杂的软件中都要根据需求来确定。

在我们这个简单的示例项目中,我们不使用RBAC方式,而是采取简单的方式,直接判断用户是否登录。如果登录,则具有所有权限,如果没有登录,则显示禁止访问信息。

二、如何将权限模型落实到代码中

最简单的方式,就是直接在需要检查权限的地方硬编码检查。
比如,要判断用户是否可以删除文章,就在删除文章的代码之前,插入一段检查的代码。

这种方式具有的优点:简单、直接、灵活,几乎无所不能。
但也有缺点:权限代码散落在代码的各个角落,无法统一管理;一旦出现bug,查找困难等……

为了让代码可以集中管理,甚至为了可以让权限检查代码和其他代码彻底分离,于是出现了各种方式,比如采用AOP(面向切面编程)等。

wojilu MVC framework 则不用那么复杂,利用 wojilu MVC framework 天然对命名空间支持的特点,我们可以很容易的做到权限代码的分离解耦。

下面我们开始加入权限检查的代码部分。

第一步,在 Admin(是wojilu.cms.Controller.Admin的简称) 命名空间下,建立一个名叫 SecurityController 的控制器:

还记得先前我们在 LoginController.CheckLogin()  检查用户登录部分,是给合法用户设置session的吗:

所以我们在 SecurityController 中,是通过session中是否有这个值来判断是否登录的。

是不是说,只要我们加了一个名叫SecurityController的一个CheckPermission方法,就能对整个命名空间下的所有代码其作用?

没错!看下目录:

wojilu MVC framework在执行某控制器之前,会先从根命名空间开始,一级一级的检查,检查每个命名空间下是否有 SecurityController 这个控制器,如果有,就执行它的 CheckPermission 方法。而您可以在 CheckPermission 方法中,判断用户的权限。如果检查未通过,您可以使用 echo/ctx.applicationComplete 等方法终止程序的运行。

再回顾一下上面的控制器:

我们可以看到,在执行 wojilu.cms.Controller.Admin 命名空间下的任何控制器之前,都会先执行这个SecurityController.CheckPermission方法!其实,系统还会先检查 wojilu.cms.Controller 命名空间下的 SecurityController ,因为我们并没有创建这个类,所以就自动跳过了。

通过这个特殊的controller,我们就有效避免了在 ArticleController, CategoryController, UserController 每个控制器的每个方法中硬编码权限代码的糟糕做法。

另外,我们还可以自定义 信息反馈页面。
看下非法访问后台的效果:

 

这个信息页面,除了我们在CheckPermission方法中返回的“非法访问,请先登录”之外,下面还有一行文字,以及一些边框、背景等样式。
其实,wojilu MVC framework 在通过 echo 显示信息的时候,是先获取 views/msg.html 文件作为模板,然后将 echo 的内容嵌入msg.html 模板之中,最后才显示的。这个模板文件在:

 

您可以修改这个文件,自定义您们系统自己的信息反馈界面。

第二步,我们还要让 wojilu.cms.Controller.Admin 命名空间下的 LoginController 绕开权限检查。毕竟,您总得让非登录用户可以访问 LoginController 吧,不然怎么登录呢?

这段代码通知 wojilu MVC framework,在执行 LoginController 的所有方法的时候,请隐藏掉 SecurityController 的权限检查动作。