首先说明,在shiro中,实际应用中在方法上添加 RequiresPermissions 或者 RequiresRoles 注解会触发aop执行验证当前Subject是否有相关权限或者角色的代码。
RequiresPermissions 的注解处理器中调用 getSubject().isPermitted(String permission) 验证。
RequiresRoles 的注解处理器中调用 getSubject().hasRole(String role) 验证。
下面从调用 getSubject().isPermitted(String permission) 开始分析整个调用过程
步骤1:默认执行DelegatingSubject中的方法:
public boolean isPermitted(String permission) {
return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
}
首先验证实例字段 PrincipalCollection principals;长度不为0,然后调用securityManager验证是否有此权限
步骤2:securityManager使用内容实例变量 Authorizer authorizer来验证权限
public boolean isPermitted(PrincipalCollection principals, String permissionString) {
return this.authorizer.isPermitted(principals, permissionString);
}
步骤3:此时authorizer的默认实现类ModularRealmAuthorizer验证权限
public boolean isPermitted(PrincipalCollection principals, String permission) {
assertRealmsConfigured();
for (Realm realm : getRealms()) {
if (!(realm instanceof Authorizer)) continue;
if (((Authorizer) realm).isPermitted(principals, permission)) {
return true;
}
}
return false;
}
可以看出,最终和验证登录一样,登录的时候把realm转换为Realm接口调用身份认证接口,而现在是把realm转换为Authorizer,调用isPermitted验证权限。
步骤4:此时调用 抽象类 abstract class AuthorizingRealm中的方法,该类实现了接口Authorizer 的isPermitted方法
public boolean isPermitted(PrincipalCollection principals, String permission) {
//把permission字符串转换为permission接口实现类的实例,例如String permission="aaa:bbb";
//会转变成接口Permission实现类中的实例字段,分成aaa和bbb两个权限放在集合中存放
Permission p = getPermissionResolver().resolvePermission(permission);
return isPermitted(principals, p);
}
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
//getAuthorizationInfo(principals)调用的就是AuthorizingRealm实现的方法了
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
步骤5:AuthorizingRealm实现的getAuthorizationInfo(principals)
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
return null;
}
AuthorizationInfo info = null;
Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
if (cache != null) {
//先到缓存中找
Object key = getAuthorizationCacheKey(principals);
info = cache.get(key);
}
if (info == null) {
// 如果缓存中没有找到,则调用模板方法,就是我们继承此类实现的doGetAuthorizationInfo
//抽象方法
info = doGetAuthorizationInfo(principals);
if (info != null && cache != null) {
Object key = getAuthorizationCacheKey(principals);
cache.put(key, info);
}
}
return info;
}
步骤6:现在已经拿到AuthorizationInfo info,这个实例中包含着我们往里面放的权限集合,doGetAuthorizationInfo(principals):
Set<String> permsSet = new HashSet<String>();
permsSet.add("lightsaber");
permsSet.add("wield");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
现在回到了步骤4里面的方法:
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
//getAuthorizationInfo(principals)调用的就是AuthorizingRealm实现的方法了
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
继续这个类里面的方法,验证权限:
protected boolean isPermitted(Permission permission, AuthorizationInfo info) {
Collection<Permission> perms = getPermissions(info);
if (perms != null && !perms.isEmpty()) {
for (Permission perm : perms) {
if (perm.implies(permission)) {
return true;
}
}
}
return false;
}
获取true或false返回到最开始的getSubject().isPermitted(String permission) ,同理验证角色的过程比较相似,只要在doGetAuthorizationInfo(principals)方法中设置 info.setRoles();