一.步骤总结
1.首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而SecurityManage接着委托给Authorizer
2.Authorizer是真正的授权者,如果我们调用如.isPermitted(“user:view”),其首先会通过PermissionResolver把字符串换成相应的permission实例
3.在进行授权之前,其会调用相应的realm获取Subject相应的角色/权限用于匹配传入的角色/权限
4.Authorizer会判断realm的角色/权限是否传入的匹配 ,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted/hasRole会返回true,否则返回false表示授权失败
二.源码解析
1.调用Subject.isPermitted/hasRole接口
boolean[] booleans = subject.isPermitted("user:insert", "user:select");
2.进入到isPermitted()中,如果有Principals就开始调用SecurityManager的isPermitted方法,即subject委托给SecurityManager
public boolean[] isPermitted(String... permissions) {
//如果有Principals就开始
if (hasPrincipals()) {
return securityManager.isPermitted(getPrincipals(), permissions);
} else {
return new boolean[permissions.length];
}
}
3.进入到isPermitted中,会看到委托给了授权器Authorizer的isPermitted方法
public boolean[] isPermitted(PrincipalCollection principals, String... permissions) {
return this.authorizer.isPermitted(principals, permissions);
}
4.进入到授权器的isPermitted方法中,在这里,我们可以看到底层是用for循环来对我们传进来的权限进行逐一比对
1)当i0时.,在isPermitted(principals, permissions[i])中,把用户信息和传进来的第一个权限传给了isPermitted方法,然后把结果赋值给了new 出来的boolean类型的数组isPermitted[ 0],
2)当i1时.,在isPermitted(principals, permissions[i])中,把用户信息和传进来的第一个权限传给了isPermitted方法,然后把结果赋值给了new 出来的boolean类型的数组isPermitted[1]
public boolean[] isPermitted(PrincipalCollection principals, String... permissions) {
assertRealmsConfigured();
if (permissions != null && permissions.length > 0) {
//先new了一个boolean的数组,数组的长度由传进来的权限个数决定,数组的默认值都是false,并开始做for循环,对每个权限进行判断是否拥有
boolean[] isPermitted = new boolean[permissions.length];
for (int i = 0; i < permissions.length; i++) {
isPermitted[i] = isPermitted(principals, permissions[i]);
}
return isPermitted;
}
return new boolean[0];
}
5.点进去isPermitted(principals, permissions[i]);在这个方法中,会先获取到所有的Realm,在这边我们自定义了一个realm.所以获取到的是我们自己定义的realm,接着(Authorizer) realm).isPermitted(principals, permission)这个的方法内部其实就是把传进来的字符串权限转成了 Permission对象
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;
}
把字符串转成了 Permission对象
public boolean isPermitted(PrincipalCollection principals, String permission) {
Permission p = getPermissionResolver().resolvePermission(permission);
return isPermitted(principals, p);
}
6.在转成了字符串后,我们进入到 return isPermitted(principals, p)中
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
7.再进入到 getAuthorizationInfo(principals)中,这一步的逻辑是
1)如果principals为空,则返回null
2)如果principals不为空,则先从缓存中获取info信息,如果info不为空,则通过principals获取key,再通过key获取info信息,info包含了该用户授权过的角色和权限
3)如果缓存中没有info,则调用 doGetAuthorizationInfo(principals);方法去获取info,这个方法就是我们自定义的myRealm中的方法,获取到info后判断是否开启了缓存,即cache是否为null,如果不为空,则把principals作为key,info作为值存到缓存中
4)最终返回info
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
return null;
}
AuthorizationInfo info = null;
if (log.isTraceEnabled()) {
log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
}
Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
if (cache != null) {
if (log.isTraceEnabled()) {
log.trace("Attempting to retrieve the AuthorizationInfo from cache.");
}
Object key = getAuthorizationCacheKey(principals);
info = cache.get(key);
if (log.isTraceEnabled()) {
if (info == null) {
log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");
} else {
log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");
}
}
}
if (info == null) {
// Call template method if the info was not found in a cache
info = doGetAuthorizationInfo(principals);
// If the info is not null and the cache has been created, then cache the authorization info.
if (info != null && cache != null) {
if (log.isTraceEnabled()) {
log.trace("Caching authorization info for principals: [" + principals + "].");
}
Object key = getAuthorizationCacheKey(principals);
cache.put(key, info);
}
}
return info;
}
- 此时第6步中的
- AuthorizationInfo info = getAuthorizationInfo(principals)就会得到info信息,并返回
return isPermitted(permission, info)
10.再进到return isPermitted(permission, info)中,看看得到是怎么进行权限认证的,这个认证的思路就是
1)先将info中包含的权限集合获取出来,并遍历这个集合,逐一和传进来的第一个权限对象permission进行比对,如果相等,就返回true,如果都不相等,就返回false
2)最后将这个结果逐一返回给最前面,就得到了boolean数组中的第一个值
3)再返回来进行第二个权限判断
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;
}