Shiro:权限控制底层解析

前面:

正如之前写的认证的过程,说授权跟认证很相似,没有错,只是授权需要手动开启,Shiro才回去进行权限的查询和对比.

流程图:

shiro的认证流程

  • 如上图,需要手动开始认证,通过.hasRole(),或者isPermitted(),分别判断用户是否具有这个角色,这个权限.注意:权限里面的字符不是"角色"+"权限",而仅仅是权限表里面存储的字段。可以通过三种方法进行开启:(1)编程式,直接在在代码中调用Subject的hasRole(),和isPermitted()方法. (2)注解式,在方法或者类的头上添加注解。(3)JSP的标签
  • (1)正如上面图片,调用hasrole(),交给securitymanager处理.
//实现subject接口
public class DelegatingSubject implements Subject {
	//交给securitymanager进行处理
   protected transient SecurityManager securityManager;
	//代码或者注释调用这个方法,getPrincipals()是获取身份集合
   public boolean hasRole(String roleIdentifier) {
       return hasPrincipals() && securityManager.hasRole(getPrincipals(), roleIdentifier);
   }
}
  • (2) manager调用自己的hasrole(),这是注意:securitymanager也是一个接口,所以这时候还是有一个类实现了这个接口并去调用hasrole()方法.

//autenticatingSecurityManager的父类的父类的父类CachingSecurityManager实现了securityManager接口
public abstract class AuthorizingSecurityManager extends AuthenticatingSecurityManager {
	//通过这个授权器来调用hasRole()方法
   private Authorizer authorizer;
   //这个就是代码一中所调用的hasRole()方法
   public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
       return this.authorizer.hasRole(principals, roleIdentifier);
   }
}
  • 通过默认的authorizer的实例对象ModularRealmAuthorizer来调用hasRole().
public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware {
   //在此处开始进行处理
   public boolean hasRole(PrincipalCollection principals, String roleIdentifier) {
   	//校验是否存在Realm对象,没有的话就抛出异常
       assertRealmsConfigured();
       
       for (Realm realm : getRealms()) {
           if (!(realm instanceof Authorizer)) continue;
           if (((Authorizer) realm).hasRole(principals, roleIdentifier)) {
               return true;
           }
       }
       return false;
   }
}
  • 如果在securityManager中配置的realm实现了authorizer接口,会使用这个Realm来调用hasRole().
@Bean("securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(SysUserRealm userRealm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        // 使用自定义Realm,同时Shiro里面只承认这一个Realm
        defaultWebSecurityManager.setRealm(userRealm);
        // 关闭Shiro自带的session
       ....
        return defaultWebSecurityManager;
    }
  • 下面是自己定义的realm
//虽然它没有实现authorizer接口,但是他的父类实现了这个接口
//所以虽然调用的是父类里面的方法,但是实例对象是这个SysUserRealm 的对象
public class SysUserRealm extends AuthorizingRealm {

}
  • 这个就是SysUserRealm 所调用的hasRole()方法.
//可以看到实现了Authorizer接口
public abstract class AuthorizingRealm extends AuthenticatingRealm
        implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware {
	
	//通过参数可以看到这个就是调用的方法
	public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
		//首先获取到AuthorizationInfo 
        AuthorizationInfo info = getAuthorizationInfo(principal);
        //看这个参数可以知道它调用的是下面的hasRole()方法
        return hasRole(roleIdentifier, info);
    }
	//这个方法是在获取到AuthorizationInfo 之后,所有的准备工作完成之后,开始进行的角色匹配
	//也就是真正的判断时候具有这个角色的核心方法
    protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
        return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
    }

}
  • 下面是获取AuthorizationInfo 的方法,同时也是AuthorizingRealm里面的方法.
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
   	
       ....
       AuthorizationInfo info = null;

       ....
   	//获取AuthorizationCatch,这个catch里面存储的是info集合,可以通过key来获取对于的info
       Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
       if (cache != null) {
         	 ....
           //这个是获取catch中存储信息的key,具体规则看你是自定义了catch还是默认catch
           Object key = getAuthorizationCacheKey(principals);
           //通过key获取到AuthorizationInfo信息,如果还从没有存储过,则为空
           info = cache.get(key);
              ....
       }
   	//如果没找到对应catch中的信息,就重新查数据库
       if (info == null) {
           // 可以看到这个方法是我们自定义的Realm里面的方法,并且现在的实例对象也是我们自定义的Realm
           info = doGetAuthorizationInfo(principals);
           // 将info存储在catch中,下次直接查询使用
           if (info != null && cache != null) {
              ....
               Object key = getAuthorizationCacheKey(principals);
               cache.put(key, info);
           }
       }

       return info;
   }
  • 下面是使用自定义的Realm里面的doGetAuthorizationInfo()方法获取info信息
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

       SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
       String account = JwtUtil.getClaim(principalCollection.toString(), Constant.ACCOUNT);
       SysUserVo sysUserVo = new SysUserVo();
       sysUserVo.setPhone(account);
       // 查询用户角色
       List<SysRole> roleDtos = sysUserMapper.findRoleByUser(sysUserVo);
       System.out.println(roleDtos.toString());
       for (SysRole roleDto : roleDtos) {
           if (roleDto != null) {
               // 添加角色
               simpleAuthorizationInfo.addRole(roleDto.getRoleName());
               // 根据用户角色查询权限
               List<SysMenuVo> sysMenuVos = SysRoleMapper.selMenuByRole(roleDto.getId());
               System.out.println(sysMenuVos.toString());
               for (SysMenuVo sysMenuVo : sysMenuVos) {
                   if (sysMenuVo != null) {
                       // 添加权限
                       System.out.println(sysMenuVo.getPermission());
                       simpleAuthorizationInfo.addStringPermission(sysMenuVo.getPermission());
                   }
               }
           }
       }
       return simpleAuthorizationInfo;
   }
  • 获取到info就开始进行角色匹配
//这个方法是在获取到AuthorizationInfo 之后,所有的准备工作完成之后,开始进行的角色匹配
   //也就是真正的判断时候具有这个角色的核心方法
   protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
   	//如果匹配成功就返回True
       return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
   }

到此核心代码已经结束,存在角色就代表授权成功,返回true,一次返回上一次,访问继续进行.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝多芬也爱敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值