鲁春利的工作笔记 ,好记性不如烂笔头
Shiro配置文件(shiro-authorize-permission.ini)
[main]
# 定义变量
# 变量名=全类名
[users]
# 用户名=密码,角色1,角色2,...,角色N
lucl=123,role1,role2
zs=123,role1
[roles]
# 角色=权限1,权限2,...,权限N
role1=user:create,user:update
role2=user:create,user:delete
单元测试
/**
* 基于资源的访问控制
*/
@Test
public void testWhetherHasPermission () {
// 1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory factory = new IniSecurityManagerFactory("classpath:shiro/authorize/shiro-authorize-permission.ini");
// 2、得到SecurityManager实例并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
// 3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("lucl", "123");
try{
// 4、登录,即身份验证
subject.login(token);
} catch (AuthenticationException e) {
// 5、身份验证失败
logger.info("用户身份验证失败");
e.printStackTrace();
}
// 用户身份得到确认
if (subject.isAuthenticated()) {
logger.info("用户登录成功。");
/**
* 进行权限判断
*/
// 判断拥有权限:user:create
Assert.assertTrue(subject.isPermitted("user:create"));
// 判断拥有权限:user:update and user:delete
Assert.assertTrue(subject.isPermittedAll("user:update", "user:delete"));
// 判断没有权限:user:view
Assert.assertFalse(subject.isPermitted("user:view"));
// 断言拥有权限:user:create
subject.checkPermission("user:create");
// 断言拥有权限:user:delete and user:update
subject.checkPermissions("user:delete", "user:update");
// 断言拥有权限:user:view 失败抛出异常
subject.checkPermissions("user:view");
} else {
logger.info("用户登录失败。");
}
// 6、退出
subject.logout();
}
isPermitted过程
package org.apache.shiro.subject.support;
public class DelegatingSubject implements Subject {
/** hasPrincipals()判断身份信息,身份信息是在login方法登录后赋值的 */
public boolean isPermitted(String permission) {
return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
}
public void login(AuthenticationToken token) throws AuthenticationException {
clearRunAsIdentitiesInternal();
/** 身份认证 */
Subject subject = securityManager.login(this, token);
PrincipalCollection principals;
String host = null;
if (subject instanceof DelegatingSubject) {
DelegatingSubject delegating = (DelegatingSubject) subject;
//we have to do this in case there are assumed identities - we don't want to lose the 'real' principals:
principals = delegating.principals;
host = delegating.host;
} else {
principals = subject.getPrincipals();
}
if (principals == null || principals.isEmpty()) {
// 异常信息
throw new IllegalStateException(msg);
}
this.principals = principals;
this.authenticated = true;
// 代码略
}
}
securityManager.isPermitted
securityManager的实现为DefaultSecurityManager,但DefaultSecurityManager无isPermitted方法。
org.apache.shiro.mgt.DefaultSecurityManager
extends org.apache.shiro.mgt.SessionsSecurityManager
extends org.apache.shiro.mgt.AuthorizingSecurityManager
extends org.apache.shiro.mgt.AuthenticatingSecurityManager
调用AuthorizingSecurityManager的isPermitted方法
package org.apache.shiro.mgt;
public abstract class AuthorizingSecurityManager extends AuthenticatingSecurityManager {
/**
* The wrapped instance to which all of this SecurityManager authorization calls are delegated.
* 授权的核心接口
*/
private Authorizer authorizer;
public AuthorizingSecurityManager() {
super();
this.authorizer = new ModularRealmAuthorizer();
}
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
return this.authorizer.isPermitted(principals, permission);
}
// 其他代码略
}
ModularRealmAuthorizer.isPermitted方法
package org.apache.shiro.authz;
public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware {
/**
* The realms to consult during any authorization check.
*/
protected Collection realms;
protected PermissionResolver permissionResolver;
protected RolePermissionResolver rolePermissionResolver;
public ModularRealmAuthorizer() {
// 无参构造方法
}
public ModularRealmAuthorizer(Collection realms) {
setRealms(realms);
}
/* 权限判断 */
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
assertRealmsConfigured();
for (Realm realm : getRealms()) {
if (!(realm instanceof Authorizer)) continue;
if (((Authorizer) realm).isPermitted(principals, permission)) {
return true;
}
}
return false;
}
} 转了一圈,具体的isPermitted还是通过最终的realm来完成(IniRealm)
org.apache.shiro.realm.text.IniRealm
extends org.apache.shiro.realm.text.TextConfigurationRealm
extends org.apache.shiro.realm.SimpleAccountRealm
extends org.apache.shiro.realm.AuthorizingRealm
AuthorizingRealm.isPermitted被调用
package org.apache.shiro.realm;
/**
* An AuthorizingRealm extends the AuthenticatingRealm's capabilities by adding Authorization (access control) support.
* @see org.apache.shiro.authz.SimpleAuthorizationInfo
* @since 0.2
*/
public abstract class AuthorizingRealm extends AuthenticatingRealm
implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware {
private PermissionResolver permissionResolver;
private RolePermissionResolver permissionRoleResolver;
public AuthorizingRealm() {
this(null, null);
}
public AuthorizingRealm(CacheManager cacheManager) {
this(cacheManager, null);
}
public AuthorizingRealm(CredentialsMatcher matcher) {
this(null, matcher);
}
public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
/** super()会调用父类的无参构造方法,也就是new AuthenticatingRealm() {this(null, new SimpleCredentialsMatcher());} */
super();
if (cacheManager != null) setCacheManager(cacheManager);
if (matcher != null) setCredentialsMatcher(matcher);
this.authorizationCachingEnabled = true;
// permissionResolver的实现类,自定义Permission时自定了也自定义了这个东西
this.permissionResolver = new WildcardPermissionResolver();
// 代码略
}
public boolean isPermitted(PrincipalCollection principals, String permission) {
// WildcardPermissionResolver.resolvePermission {return new WildcardPermission(permissionString);}
Permission p = getPermissionResolver().resolvePermission(permission);
return isPermitted(principals, p);
}
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
/**
* getAuthorizationInfo(principals)实际返回的是SimpleAccount;
* 如果我们在自定义的Realm中实现了info.add("system:edit:1"),那么SimpleAccount就获取到了其拥有的权限列表:
* 说明:也就是shiro不维护权限信息,其应该具有的权限信息是由业务系统根据实际情况来设定的
* isPermitted会比较传入的权限字符串,是否在实际设定的权限列表中(权限列表一般根据登录用户权限从数据库中读取并加载)
*/
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
/** 最终的判断方法(权限集合是在Realm实现时添加的权限列表,如info.add("system:edit:1")) */
protected boolean isPermitted(Permission permission, AuthorizationInfo info) {
Collection perms = getPermissions(info);
if (perms != null && !perms.isEmpty()) {
for (Permission perm : perms) {
/** Permission的implies方法总算是被调用到了 */
if (perm.implies(permission)) {
return true;
}
}
}
return false;
}
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
return null;
}
AuthorizationInfo info = null;
// 代码略,主要实现从缓存中获取授权数据
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.
// 代码略,获取后重新加入缓存中
}
return info;
}
// 该类的doGetAuthorizationInfo方法为抽象方法,需要子类根据身份信息实现自己的授权
protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);
}
SimpleAccountRealm.doGetAuthorizationInfo方法
package org.apache.shiro.realm;
public class SimpleAccountRealm extends AuthorizingRealm {
// 部分代码略
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = getUsername(principals);
USERS_LOCK.readLock().lock();
try {
return this.users.get(username); // 返回SimpleAccount
} finally {
USERS_LOCK.readLock().unlock();
}
}
}
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com