zoukankan      html  css  js  c++  java
  • (六)授权(下):自定义permission

    一、Authorizer、PermissionResolver及RolePermissionResolver

    Authorizer的职责是进行授权(访问控制),是Shiro API中授权核心的入口点,其提供了相应的角色/权限判断接口,具体请参考其Javadoc。SecurityManager继承了Authorizer接口,且提供了ModularRealmAuthorizer用于多Realm时的授权匹配。PermissionResolver用于解析权限字符串到Permission实例,而RolePermissionResolver用于根据角色解析相应的权限集合。

    二、案例

    • shiro.ini
    [main]  
    #自定义authorizer  
    authorizer=org.apache.shiro.authz.ModularRealmAuthorizer  
    #自定义permissionResolver  
    #permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver  
    permissionResolver=servlet.BitAndWildPermissionResolver
    authorizer.permissionResolver=$permissionResolver  
    #自定义rolePermissionResolver  
    rolePermissionResolver=servlet.MyRolePermissionResolver  
    authorizer.rolePermissionResolver=$rolePermissionResolver  
      
    securityManager.authorizer=$authorizer 
    
    #自定义realm 一定要放在securityManager.authorizer赋值之后(因为调用setRealms会将realms设置给authorizer,并给各个Realm设置permissionResolver和rolePermissionResolver)  
    realm=realms.MyRealm1  
    securityManager.realms=$realm   
    • 对于ModularRealmAuthorizer,相应的AuthorizingSecurityManager会在初始化完成后自动将相应的realm设置进去,我们也可以通过调用其setRealms()方法进行设置
    • BitPermission.java
    package servlet;
    
    import org.apache.shiro.authz.Permission;
    
    /**
     * BitPermission用于实现位移方式的权限,如规则是:
     * 
     * 权限字符串格式:+资源字符串+权限位+实例ID;以+开头中间通过+分割;权限:0 表示所有权限;1 新增(二进制:0001)、2
     * 修改(二进制:0010)、4 删除(二进制:0100)、8 查看(二进制:1000);如 +user+10 表示对资源user拥有修改/查看权限。
     * 
     * @author Administrator
     *
     */
    public class BitPermission implements Permission {
        private String resourceIdentify;
        private int permissionBit;
        private String instanceId;
    
        public BitPermission(String permissionString) {
            String[] array = permissionString.split("\+");
            if (array.length > 1) {
                resourceIdentify = array[1];
            }
            if (resourceIdentify == null || resourceIdentify.equals("")) {
                resourceIdentify = "*";
            }
            if (array.length > 2) {
                permissionBit = Integer.valueOf(array[2]);
            }
            if (array.length > 3) {
                instanceId = array[3];
            }
            if (instanceId == null || resourceIdentify.equals("")) {
                instanceId = "*";
            }
        }
    
        public boolean implies(Permission p) {
            if (!(p instanceof BitPermission)) {
                return false;
            }
            BitPermission other = (BitPermission) p;
            if (!("*".equals(this.resourceIdentify) || this.resourceIdentify.equals(other.resourceIdentify))) {
                return false;
            }
            if (!(this.permissionBit == 0 || (this.permissionBit & other.permissionBit) != 0)) {
                return false;
            }
            if (!("*".equals(this.instanceId) || this.instanceId.equals(other.instanceId))) {
                return false;
            }
            return true;
        }
    }
    • BitPermission用于实现位移方式的权限,如规则是:

      权限字符串格式:+资源字符串+权限位+实例ID;以+开头中间通过+分割;权限:0 表示所有权限;1 新增(二进制:0001)、2 修改(二进制:0010)、4 删除(二进制:0100)、8 查看(二进制:1000);如 +user+10 表示对资源user拥有修改/查看权限。

    • Permission接口提供了boolean implies(Permission p)方法用于判断权限匹配的.
    • MyRolePermissionResolver.java:RolePermissionResolver用于根据角色字符串来解析得到权限集合
      public class MyRolePermissionResolver implements RolePermissionResolver {  
          public Collection<Permission> resolvePermissionsInRole(String roleString) {  
              if("role1".equals(roleString)) {  
                  return Arrays.asList((Permission)new WildcardPermission("menu:*"));  
              }  
              return null;  
          }  
      }   
       
    • 自定义Realm.java
    public class MyRealm1 extends AuthorizingRealm{
    
        /**
         * 判断授权的
         */
        @Override
          protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();  
            authorizationInfo.addRole("role1");  
            authorizationInfo.addRole("role2");  
            authorizationInfo.addObjectPermission(new BitPermission("+user1+10"));  
            authorizationInfo.addObjectPermission(new WildcardPermission("user1:*"));  
            authorizationInfo.addStringPermission("+user2+10");  
            authorizationInfo.addStringPermission("user2:*");  
            return authorizationInfo;  
        }  
    
        /**
         * 判断认证的
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            String userName=token.getPrincipal().toString();
            String passWord=new String((char[])token.getCredentials());
            
            if(!userName.equals("zhang")) throw new UnknownAccountException("Realm1 用户名错误");
            if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm1 密码错误");
            
            return new SimpleAccount(userName, passWord, getName());
        }
    
    }
    • 此次还要注意就是不能把我们自定义的如“+user1+10”配置到INI配置文件,即使有IniRealm完成,因为IniRealm在new完成后就会解析这些权限字符串,默认使用了WildcardPermissionResolver完成,即此处是一个设计权限,如果采用生命周期(如使用初始化方法)的方式进行加载就可以解决我们自定义permissionResolver的问题。
    public class TestMain {
        public static void main(String[] args) {
            SecurityManager securityManager=new IniSecurityManagerFactory("classpath:shiro.ini").getInstance(); 
            SecurityUtils.setSecurityManager(securityManager);
            
            Subject subject=SecurityUtils.getSubject();
            subject.login(new UsernamePasswordToken("zhang", "123"));
    
            //通过二进制位的方式表示权限  
            System.out.println(subject.isPermitted("+user1+2"));//新增权限  
            System.out.println(subject.isPermitted("+user1+8"));//查看权限
            System.out.println(subject.isPermitted("+user2+10"));//新增及查看  
      
            System.out.println(subject.isPermitted("+user1+4"));//没有删除权限  
            System.out.println(subject.isPermitted("menu:view"));//通过MyRolePermissionResolver解析得到的权限  
        }
    }

    • 流程如下:

    1、首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer;

    2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;

    3、在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;

    4、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否则返回false表示授权失败。

     本例中的流程大概是:

    1.System.out.println(subject.isPermitted("+user1+2"));
    2.BitAndWildPermissionResolver把字符串转换成相应的Permission实例(调用BitPermission的构造方法,参数为"+user1+2",解析该参数并封装到BitPermission的成员变量中,即将该参数转为BitPermission实例)
    3.MyRealm1中的doGetAuthorizationInfo方法获取Subject相应的角色/权限用于匹配传入的角色/权限

  • 相关阅读:
    从句分析
    artDialog ( v 6.0.2 ) content 参数引入页面 html 内容
    Java实现 LeetCode 13 罗马数字转整数
    Java实现 LeetCode 13 罗马数字转整数
    Java实现 LeetCode 13 罗马数字转整数
    Java实现 LeetCode 12 整数转罗马数字
    Java实现 LeetCode 12 整数转罗马数字
    Java实现 LeetCode 12 整数转罗马数字
    Java实现 LeetCode 11 盛最多水的容器
    Java实现 LeetCode 11 盛最多水的容器
  • 原文地址:https://www.cnblogs.com/shyroke/p/7838115.html
Copyright © 2011-2022 走看看