下面详细介绍在进行授权时,Shiro的内部处理机制。
如上图,我们通过Shiro架构图的授权部分,来说明Shiro授权内部的处理顺序:
1.应用程序或框架代码调用任何Subject的hasRole*,checkRole*,isPermitted*,或者checkPermission*方法的变体,传递任何所需的权限或角色内容。
2.Subject的实例,通常是DelegatingSubject(或子类)代表应用程序的SecurityManager通过调用securityManager的各自相同的hasRole*,checkRole*,isPermitted*,或checkPermission*方法的变体(SecurityManager实现org.apache.shiro.authz.Authorizer接口,他定义了所有Subject具体的授权方法)。
3.SecurityManager,作为一个基本的“保护伞”组件,接替/代表它内部的org.apache.shiro.authz.Authorizer实例通过调用authorizer各自的hasRole*,checkRole*,isPermitted*,或者checkPermissions*方法。默认情况下,authorizer实例是一个ModularRealmAuthorizer实例,它支持协调任何授权操作过程中的一个或多个Realm实例。
4.每个配置好的Realm被检查是否实现了相同的Authorizer接口。如果是,Realm各自的hasRole*,checkRole*,isPermitted*,或checkPermission*方法将被调用。
如前所述,ShiroSecurityManager的默认实现是使用一个ModularRealmAuthorizer实例。ModularRealmAuthorizer同样支持单一的Realm,以及多个Realm的应用。
对于任何授权操作,ModularRealmAuthorizer将遍历其内部的Realm集合,并按顺序与每一个进行交互。每个Realm的交互功能如下:如果Realm自己实现了Authorizer接口,它的各个Authorizer方法(hasRole*,checkRole*,isPermitted*,或checkPermission*)将被调用;如果Realm不实现Authorizer接口,它会被忽略。
当存在多个Realms时,ModularRealmAuthorizer根据SecurityManager的配置获得对Realm实例的访问。当执行授权操作时,它会遍历该集合,同时对于每一个自己实现Authorizer接口的Realm,调用Realm各自的Authorizer方法(如hasRole*,checkRole*,isPermitted*,或checkPermission*)。
如果Realm的方法导致异常,该异常将会以AuthorizationException的形式传递给调用者。同时任何剩余的Realm将不会被该授权操作所访问。如果该Realm的方法是一个返回布尔值的hasRole*或者isPermitted*的变体,并且该返回值为true,真值将会立即被返回,同时任何剩余的Realm都将不会访问。这种处理是作为提高性能的一种行为。
当执行基于字符串的权限检查时,Shiro默认实现是将该字符串转换成一个实际的Permission实例。所有ShiroRealm的默认实现是内部的WildcardPermissionResolver,它采用Shiro的WildcardPermission字符串格式。你也可以创建自己的PermissionResolver的实现,支持自己的权限字符串语法。可以将你的PermissionResolver设置为全局的。例如:
globalPermissionResolver=com.foo.bar.authz.MyPermissionResolver … securityManager.authorizer.permissionResolver=$globalPermissionResolver ... |
也可以为特定的Realm设置自己创建的PermissionResolver。例如:
permissionResolver=com.foo.bar.authz.MyPermissionResolver realm=com.foo.bar.realm.MyCustomRealm realm.permissionResolver=$permissionResolver ... |
与PermissionResolver有相似概念的RolePermissionResolver通过角色执行权限检查。RolePermissionResolver的关键区别是输入的字符串是一个角色名,而不是一个权限字符串。
在Shiro中授权有3种方式:
l编写代码——你可以在你的Java代码中用像if和else块的结构执行授权检查。
lJDK的注解——你可以添加授权注解给你的Java方法。
lJSP/GSP标签库——你可以控制基于角色和权限的JSP或者GSP页面输出。