日期:2014-05-16  浏览次数:20845 次

Apache Shiro 授权
Apache Shiro 授权



授权,亦即访问控制,是管理资源访问的过程,换言之,也就是控制在一个程序中“谁”有权利访问“什么”。

授权的例子有:是否允许这个用户查看这个页面,编辑数据,看到按钮,或者从这台打印机打印?这些决定一个用户可以访问什么的决断。



授权组件

授权有三个核心组件,在Shiro中我们经常要用到它们:权限(permissions)、角色(roles)和用户(users)。



权限(Permissions)

权限是Apache Shiro中安全策略最基本的组件,它们是一组关于行为的基本指令,以明确表示在一个程序中什么可以做。一个很好定义的权限指令必须描述资源以及当一个Subject与这些资源交互时什么动作可以执行。



下面是一些权限指令的例子:

打开一个文件;

查看“/user/list”页面;

打印文档;

删除“Jsmith”用户。



大部分资源都支持基本的CRUD(create,read,update,delete)操作,而任何能识别特定资源类型的动作也是支持的的。最基础的思想是在资源和动作的基础上设置的最小量的权限指令。



当看到权限时,也许最重要的事情是意识到一个权限指令没有描述“谁”可以执行这个动作,它们只是一些“什么”可以做的指令。



权限只描述行为

权限指令只描述行为(和资源相关的动作),并不关心“谁”有能力执行这个动作。



定义“谁”(用户)被允许做“什么”(权限)需要用一些方法将权限赋给用户,这通常取决于程序的数据模型而且经常在程序中发生改变。



例如,一组权限可以归于一个角色而角色与一个或多个用户对象关联,或者一些程序可以有一组用户而一个组可以指定一个角色,在这里关系将被传递也就是说组内用户隐含被赋予角色的权限。



有很多方式可以将权限赋予用户--程序根据需求决定如何设计。



我们稍后讨论shiro如何判断一个Subject是否被允许。



权限粒度

上面的权限示例都是对资源(门、文件、客户等)指定的动作(打开、读、删除等),在一些场景中,他们也会指定非常细粒度的“实例级别”行为--例如,“删除”(delete)名为“Jsmith”(实例标识)的“用户”(resource type),在Shiro中,你可以精确定义指令到所能细化到的程度。



我们在Shiro的Permissions文档中详细讨论权限粒度和权限指令的“级别”。



角色

角色是一个实体名,代表一组行为或职责,这些行为在程序中转换为你可以或者不能做的事情。角色通常赋给用户帐号,关联后,用户就可以“做”属于不同角色的事情。



有两种有效的角色,Shiro都支持。



隐含角色:大部分用户隐含创建角色:程序只是在一个角色名称上隐含了一组行为(也就是权限),使用隐含角色时,在软件级别不会说“某角色允许执行行为A、B和C”,行为隐含于一个单独的名字中。



潜在的安全隐患

虽然这是一个非常简单和常用的方法,但隐含的角色可能会增加软件的维护成本和管理问题。

例如,如果你想增加或删除一个角色,或者重定义角色的行为怎么办?你不得不重新打开代码修改所有已更改角色的检测,每次都需要这样做,这还没提到其引起的执行代价(重测试,通过质量验证,关闭程序,升级软件,重启程序等)。

对于简单程序这种方法可能适用(比如只有一个'admin'角色和'everyone else'角色),但复杂的程序中,这会成为你程序生命周期中一个主要的问题,会给你的软件带来很大的维护代价。



明确角色:明确角色本质上是集合了实际权限指令的一个名字,在这种形式下,程序(以及shiro)准确知道是否拥有特定的角色意味着什么,因为它确切知道某行为是否可以执行,不用猜测或隐喻一个特定的角色可以或不可以做什么。



shiro团队提倡使用权限和明确角色替代原始的隐含方法,你可以对程序安全提供更强的控制。



基于资源的访问控制

读一下Les Hazlewood的文章:The New RBAC: Resource-Based Access Control,这篇文章深入讨论了使用权限和明确角色(以及对源代码的影响)代替旧的隐含角色方法的好处。



用户

一个用户本质上是程序中的“谁”,如同我们前面提到的,Subject实际上是shiro的“用户”概念。



用户(Subjects)通过与角色或权限关联被允许执行程序内特定的动作,程序数据模型确切定义了Subject是否允许做什么事情。



例如,在你的数据模型中,你定义了一个普通的用户类并且直接为其设置了权限,或者你只是直接给角色设置了权限,然后将用户与该角色关联,通过这种关联,用户就“有”了角色所具备的权限,或者你也可以通过“组”的概念完成这件事,这取决于你程序的设计。



数据模型定义了如何进行授权,Shiro依赖一个Realm实现将你的数据模型关联转换成Shiro可以理解的内容,我们将稍后讨论Realms。



最终,Realm实现是与你的数据源(RDBMS,LDAP等)所做的交流,Realm用来告知Shiro是否角色或权限存在,你可以完全控制你的授权模型如何创建和定义。



授权对象

在Shiro中执行授权可以有三种途径:

程序中授权--你可以在你的JAVA代码中执行用类似于if和else的结构来执行法令检查。

JDK 注解--你可以在你的JAVA方法上附加授权注解

JSP/GSP标签--你可以基于角色和权限控制JSP或GSP页面输出。



程序中授权

直接在程序中为当前Subject实例授权可能是最简单也最常用的方法。



基于角色的授权

如果你要基于简单/传统的隐含角色名进行访问掏,你可以执行角色检查:



角色检查

如果你想简单地检查一下当前Subject是否拥有一个角色,你可以在一个实例上调用hasRole*方法的变形。

例如,查看一个Subject是否有特定(单独)的角色,你可以调用subject.hasRole(roleName)方法,做出相应的反馈。

Subject currentUser = SecurityUtils.getSubject();



if (currentUser.hasRole("administrator")) {

    //show the admin button

} else {

    //don't show the button?  Grey it out?

}



下面是你可以根据需要调用的函数:

hasRole(String roleName)

如果Subject指定了特定的角色返回真,否则返回假;

hasRoles(List roleNames)

返回一个与参数顺序相对应的hasRole结果数组,当一次有多个角色需要检测时非常有用(如定制一个