前言
围绕上篇文章(地址:http://blog.csdn.net/fjekin/article/details/79141843),这节来看下shiro是如何实现权限授权的?
Coding
/**
* 权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
IShiro shiroFactory = ShiroFactroy.me();
ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
List<Long> roleList = shiroUser.getRoleList();
Set<String> permissionSet = new HashSet<>();
Set<String> roleNameSet = new HashSet<>();
for (Long roleId : roleList) {
List<String> permissions = shiroFactory.findPermissionsByRoleId(roleId);
if (permissions != null) {
for (String permission : permissions) {
if (ToolUtil.isNotEmpty(permission)) {
permissionSet.add(permission);
}
}
}
String roleName = shiroFactory.findRoleNameByRoleId(roleId);
roleNameSet.add(roleName);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissionSet);
info.addRoles(roleNameSet);
return info;
}
在自定义Realm的doGetAuthorizationInfo方法中,可以看出,通过PrincipalCollection获取shiro存储对象,再通过信息查询该对象相关内容,最后存放到SimpleAuthorizationInfo中。那么, PrincipalCollection是什么呢?存储到SimpleAuthorizationInfo对象中的权限信息又是如何跟前台访问信息如何进行校验呢?
通过查看继承关系(快捷方式:选中名称+F4),实现类SimplePrincipalCollection通过认证时候存储的SimpleAuthenticationInfo,以集合方式获取到存储的ShiroUser对象。
/**
* Returns the first available principal from any of the {@code Realm} principals, or {@code null} if there are
* no principals yet.
* <p/>
* The 'first available principal' is interpreted as the principal that would be returned by
* <code>{@link #iterator() iterator()}.{@link java.util.Iterator#next() next()}.</code>
*
* @inheritDoc
*/
public Object getPrimaryPrincipal() {
if (isEmpty()) {
return null;
}
return iterator().next();
}
权限方面,首先必定是先校验是否同个用户,其次再判断是否有请求地址权限。
通过调用org.apache.shiro.subject.Subject.isPermitted(String permission)接口,委托给SecurityManager,而SecurityManager接着委托给Authorizer。
public class DelegatingSubject implements Subject {
private static final Logger log = LoggerFactory.getLogger(DelegatingSubject.class);
private static final String RUN_AS_PRINCIPALS_SESSION_KEY =
DelegatingSubject.class.getName() + ".RUN_AS_PRINCIPALS_SESSION_KEY";
protected PrincipalCollection principals;
protected boolean authenticated;
protected String host;
protected Session session;
/**
* @since 1.2
*/
protected boolean sessionCreationEnabled;
protected transient SecurityManager securityManager;
......
public boolean isPermitted(Permission permission) {
return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
}
public boolean[] isPermitted(String... permissions) {
if (hasPrincipals()) {
return securityManager.isPermitted(getPrincipals(), permissions);
} else {
return new boolean[permissions.length];
}
}
public boolean[] isPermitted(List<Permission> permissions) {
if (hasPrincipals()) {
return securityManager.isPermitted(getPrincipals(), permissions);
} else {
return new boolean[permissions.size()];
}
}
......
}
public interface SecurityManager extends Authenticator, Authorizer, SessionManager
Authorizer是真正的授权者,而它的实现类,就是我们自定义Realm的父类AuthorizingRealm。
public boolean isPermitted(PrincipalCollection principals, String permission) {
Permission p = getPermissionResolver().resolvePermission(permission);
return isPermitted(principals, p);
}
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
//visibility changed from private to protected per SHIRO-332
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;
}
PermissionResolver解析器通过resolvePermission()把字符串转换成Permission实例,再通过PrincipalCollection获取对应的AuthorizationInfo用户信息,而该对象存储权限信息就是我们在权限认证部分set进去的(本质就是set和get),最后通过implies()匹配。
通过继承关系,可以看出Permission中implies()具体实现是在父类WildcardPermission,实际上就是以集合包含关系方式来做判断。
public boolean implies(Permission p) {
// By default only supports comparisons with other WildcardPermissions
if (!(p instanceof WildcardPermission)) {
return false;
}
WildcardPermission wp = (WildcardPermission) p;
List<Set<String>> otherParts = wp.getParts();
int i = 0;
for (Set<String> otherPart : otherParts) {
// If this permission has less parts than the other permission, everything after the number of parts contained
// in this permission is automatically implied, so return true
if (getParts().size() - 1 < i) {
return true;
} else {
Set<String> part = getParts().get(i);
if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {
return false;
}
i++;
}
}
// If this permission has more parts than the other parts, only imply it if all of the other parts are wildcards
for (; i < getParts().size(); i++) {
Set<String> part = getParts().get(i);
if (!part.contains(WILDCARD_TOKEN)) {
return false;
}
}
return true;
}
Ending
无论是登录还是权限,大体上都是跟平时处理的思维方式一致,只不过shiro把它封装起来而已。因此,总结出一点,在看源码的时候,最好是先思考一下,如果让你去实现的话,会怎么做?一来,会有种思维方式引导着你,慢慢探索,有种豁然开朗、解密的感觉;其次,可以吸收代码设计模式。
文章如有笔误,请及时留言相告!!!欢迎加群一起学习,QQ:583138104
相关代码下载
&spm=1001.2101.3001.5002&articleId=79192424&d=1&t=3&u=02a337d77cd54701aaaef6a0857f1340)
429

被折叠的 条评论
为什么被折叠?



