1. Wildcard Permissions
为了易读和简化处理,Shiro提供了强大且直观的权限语法,即WildcardPermission(通配符权限)。
1.1 Simple Usage
假设你想保护公司打印机的使用,一些人可以使用打印机,一些人只能查看打印机服务器队列中的任务。最简单的方式就是定义一个queryPrinter权限,然后检查用户是否具有这个权限:
这段代码等同于:
这种基于字符串式权限的使用,只适用于简单的应用。你可以赋予用户*权限,意味着用户拥有应用中所有的权限。
A. Multiple Parts
WildcardPermission支持多级配置。对于赋予用户"printer:print"和"printer:query"权限,可以简化为:
然后,可以这样执行验证:
它将返回true。
B. All Values
如果想赋予用户某一模块全部的权限,比如,将打印机的3项操作query, print, 和manage权限都赋予用户,可以这样配置:
也可以这么配置:
那么,对于"printer:XXX"的所有检查,都将返回true。使用这种方式,在新增一个操作时,你就无需再更改权限配置了。可以在任何地方使用通配符,比如,赋予用户所有域的view权限:
那么,对"foo:view"的检查将返回true。
1.2 Instance-Level Access Control
另一个方式是使用实例级访问控制列表。需要配置三部分内容:第一部分代表域级,第二部分代表行为级,第三部分代表实例级。
第一个配置定义了ID为lp7200实例对printer(打印机)具有query(查询)权限。
第二个配置定义了ID为epsoncolor实例对printer具有print(打印)权限。
然后执行检查权限:
这种方式有利于体现用户的权限。但是,如果为所有的打印机定义实例,不利于扩展,特别是在新增一台打印机的时候。你可以使用通配符替代:
通配符有利于扩展,因为它也包含了新增打印机。也可以这样配置,拥有所有打印机的所有权限:
或者某台打印机的所有操作权限:
或某台打印机的某些操作权限:
通配符"*"和",",可以在三部分内容的任何一部分进行使用。
A. Missing Parts
最后需要注意的是,对于这三部分的配置,缺失的部分表示这个用户拥有所有这部分对应的值。
等同于:
而
等同于
但是,缺失的部分只能从后开始:
不等同于
2. Checking Permissions
使用通配符构建的权限分配,具有方便性,可伸缩性。对于想使用实例为lp7200的打印机打印文档,需要这样检查:
这种检查直观的反映了用户的操作。而以下这种方式就不那么直观了:
为什么?因为第二个例子里,你必须有所有打印机的打印权限才行("printer:print"等同于"printer:print:*")。假设当前的用户不具有所有打印机的打印权限,而只具有lp7200和epsoncolor两台打印机的权限,那么在第二个例子中,就不允许其执行在lp7200和epsoncolor上的打印操作了,这是错误的。 实践中,最好指定完整的字符权限。
3. Implication, not Equality
为什么运行时权限检查要尽可能详细,而权限分配时可以简化呢?因为权限检查是依据隐式的业务逻辑,而不是简单的相等比较。就是说,如果用户被指定"user:*"权限,用户可以执行"user:view"操作。字符串"user:*"不等于"user:view",但是前者隐式的具有后者的操作。为了支持这种隐式的规则,所有权限都被转义为org.apache.shiro.authz.Permission接口,因此,隐式的业务逻辑可以在运行时执行。这篇文档中使用的通配符都被转换为了org.apache.shiro.authz.permission.WildcardPermission实例。
还有更多通配符权限的例子:
隐式表示其具有删除用户的权限:
同样:
隐式表示其具有更新用户ID 12345的权限:
还有:
隐式表示其具有所有打印机打印的权限。
4. Performance Considerations
虽然WildcardPermission可以解决80-90%的用例,但是它并不是解决大量权限存储和验证最好的方案。
Shiro支持CacheManage,将用户,角色,权限缓存起来,然后执行验证,将大大提高验证效率。
为了易读和简化处理,Shiro提供了强大且直观的权限语法,即WildcardPermission(通配符权限)。
1.1 Simple Usage
假设你想保护公司打印机的使用,一些人可以使用打印机,一些人只能查看打印机服务器队列中的任务。最简单的方式就是定义一个queryPrinter权限,然后检查用户是否具有这个权限:
subject.isPermitted("queryPrinter")
这段代码等同于:
subject.isPermitted( new WildcardPermission("queryPrinter") )
这种基于字符串式权限的使用,只适用于简单的应用。你可以赋予用户*权限,意味着用户拥有应用中所有的权限。
A. Multiple Parts
WildcardPermission支持多级配置。对于赋予用户"printer:print"和"printer:query"权限,可以简化为:
printer:print,query
然后,可以这样执行验证:
subject.isPermitted("printer:query")
它将返回true。
B. All Values
如果想赋予用户某一模块全部的权限,比如,将打印机的3项操作query, print, 和manage权限都赋予用户,可以这样配置:
printer:query,print,manage
也可以这么配置:
printer:*
那么,对于"printer:XXX"的所有检查,都将返回true。使用这种方式,在新增一个操作时,你就无需再更改权限配置了。可以在任何地方使用通配符,比如,赋予用户所有域的view权限:
*:view
那么,对"foo:view"的检查将返回true。
1.2 Instance-Level Access Control
另一个方式是使用实例级访问控制列表。需要配置三部分内容:第一部分代表域级,第二部分代表行为级,第三部分代表实例级。
printer:query:lp7200
printer:print:epsoncolor
第一个配置定义了ID为lp7200实例对printer(打印机)具有query(查询)权限。
第二个配置定义了ID为epsoncolor实例对printer具有print(打印)权限。
然后执行检查权限:
if ( SecurityUtils.getSubject().isPermitted("printer:query:lp7200") {
// Return the current jobs on printer lp7200
}
这种方式有利于体现用户的权限。但是,如果为所有的打印机定义实例,不利于扩展,特别是在新增一台打印机的时候。你可以使用通配符替代:
printer:print:*
通配符有利于扩展,因为它也包含了新增打印机。也可以这样配置,拥有所有打印机的所有权限:
printer:*:*
或者某台打印机的所有操作权限:
printer:*:lp7200
或某台打印机的某些操作权限:
printer:query,print:lp7200
通配符"*"和",",可以在三部分内容的任何一部分进行使用。
A. Missing Parts
最后需要注意的是,对于这三部分的配置,缺失的部分表示这个用户拥有所有这部分对应的值。
printer:print
等同于:
printer:print:*
而
printer
等同于
printer:*:*
但是,缺失的部分只能从后开始:
printer:lp7200
不等同于
printer:*:lp7200
2. Checking Permissions
使用通配符构建的权限分配,具有方便性,可伸缩性。对于想使用实例为lp7200的打印机打印文档,需要这样检查:
if ( SecurityUtils.getSubject().isPermitted("printer:print:lp7200") ) {
//print the document to the lp7200 printer
}
这种检查直观的反映了用户的操作。而以下这种方式就不那么直观了:
if ( SecurityUtils.getSubject().isPermitted("printer:print") ) {
//print the document
}
为什么?因为第二个例子里,你必须有所有打印机的打印权限才行("printer:print"等同于"printer:print:*")。假设当前的用户不具有所有打印机的打印权限,而只具有lp7200和epsoncolor两台打印机的权限,那么在第二个例子中,就不允许其执行在lp7200和epsoncolor上的打印操作了,这是错误的。 实践中,最好指定完整的字符权限。
3. Implication, not Equality
为什么运行时权限检查要尽可能详细,而权限分配时可以简化呢?因为权限检查是依据隐式的业务逻辑,而不是简单的相等比较。就是说,如果用户被指定"user:*"权限,用户可以执行"user:view"操作。字符串"user:*"不等于"user:view",但是前者隐式的具有后者的操作。为了支持这种隐式的规则,所有权限都被转义为org.apache.shiro.authz.Permission接口,因此,隐式的业务逻辑可以在运行时执行。这篇文档中使用的通配符都被转换为了org.apache.shiro.authz.permission.WildcardPermission实例。
还有更多通配符权限的例子:
user:*
隐式表示其具有删除用户的权限:
user:delete
同样:
user:*:12345
隐式表示其具有更新用户ID 12345的权限:
user:update:12345
还有:
printer
隐式表示其具有所有打印机打印的权限。
printer:print
4. Performance Considerations
虽然WildcardPermission可以解决80-90%的用例,但是它并不是解决大量权限存储和验证最好的方案。
Shiro支持CacheManage,将用户,角色,权限缓存起来,然后执行验证,将大大提高验证效率。