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相应的角色/权限用于匹配传入的角色/权限

  • 相关阅读:
    Android 关于调用系统内已安装的相机问题
    bae中的wordpress:正在执行例行维护,请一分钟后回来,时间过长任然不行的解决办法
    CefSharp 拦截WebSocket发送和接收数据 WS
    CefSharp发送POST请求、GET请求
    CefSharp 拦截Request、Response获取文件内容js、css、图片、CefSharp拦截ajax内容等
    CefSharp动态设置代理IP、设置UserAgent等 UA Proxy
    CefSharp QQ群提取
    CefSharp 免登陆
    CefSharp过天猫、淘宝验证码、滑动验证码、cefsharp高版本
    Cefsharp实现拼多多 后台 多开,免登录
  • 原文地址:https://www.cnblogs.com/shyroke/p/7838115.html
Copyright © 2011-2022 走看看