• shiro学习笔记_0500_授权


    1,授权:给身份认证通过的人,授予他可以访问某些资源的权限。

    2,权限粒度:分为粗粒度细粒度。

      粗粒度:例如对 user 的 crud,也就是通常所说的对的操作。

      细粒度:对表中记录的操作。如 只允许查询id为1的user的工资。Shiro一般管理的是粗粒度的权限。比如,菜单,按钮,url。一般细粒度的权限是通过业务来控制的。

    3,角色:权限的集合。

      角色有两个概念:

      隐式角色,好像就是说传统的基于角色的访问控制。但是如果想添加或删除一个角色,或者重新定义一个角色的行为,需要修改大量代码,维护麻烦。

      显式角色,基于资源的访问控制。

      Shiro 团队提倡使用权限和显式角色,两者区别看这个家伙的文章:rbac新解

    4,权限表示规则:资源:操作:实例。可以用通配符表示。

      如:user:add 表示对user有添加的权限;user:* 表示对user有所有操作的权限;user:delete:100表示对user标识为100的记录有删除的权限。

    5,shiro中的权限流程:

    =======================================================================

    6,例子程序:

    (认证使用ini配置)

    新建maven项目,项目结构:

    maven依赖:

    <dependencies>  
          <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId> 
            <version>1.3.2</version> 
        </dependency> 
        
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>  
        
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        
        <dependency>  
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId> 
            <version>1.7.5</version>
        </dependency> 
      </dependencies> 

    log4j配置:

    log4j.rootLogger=info, stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

    shiro.ini配置:

    定义了两个用户: zhangsan/1111,lisi/1111,两个角色:role1,role2,role1有对user的add、update、delete权限,role2有对user的所有权限。

    [users]
    zhangsan=1111,role1
    lisi=1111,role2
    [roles]
    role1=user:add,user:update,user:delete
    role2=user:*

    测试程序:

    package com.lhy.shiro;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Set;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.Permission;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.Factory;
    
    public class AuthorizationDemo {
    
        public static void main(String[] args) {
            //1,创建SecurityManager工厂  读取shiro配置文件
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            //2  通过securityManager工厂获取SecurityManager实例
            SecurityManager securityManager = factory.getInstance();
            //3 将SecurityManager 对象设置到运行环境
            SecurityUtils.setSecurityManager(securityManager);
            //4 通过SecurityUtils获取主体subject
            Subject subject = SecurityUtils.getSubject();
            try {
                //5.假设登录名是zhangsan  密码是1111
                UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","1111");
                //6,登录,进行用户身验证 
                subject.login(token);
                //通过subject判断用户是否通过验证
                if(subject.isAuthenticated()){
                    System.out.println("用户登录成功!"); 
                }
            } catch (UnknownAccountException e) { 
                e.printStackTrace();
                System.out.println("用户名或密码错误!"); 
            }catch (IncorrectCredentialsException e) {
                System.out.println("用户名或密码错误!");
            }
            
            //****************基于【角色】的授权 *********************
            //hasRole判断一个权限
            boolean flag = subject.hasRole("role1");
            System.out.println(flag);
            
            /**
             * hasAllRoles:判断是否有给定的【全部角色】
             * 参数类型:Collection<String>
             * 返回  boolean 
             */
            flag = subject.hasAllRoles(Arrays.asList("role1","role2","role3"));
            System.out.println("授权-hasAllRoles方法-是否有  role1,role2,role3全部角色---"+flag);
            
            /**
             * hasRoles方法,逐个判断有给定【角色中的哪些】,返回boolean[] 
             * 参数类型:List<String> 
             */
            boolean[] flags = subject.hasRoles(Arrays.asList("role1","role2"));
            for (int i = 0; i < flags.length; i++) {
                System.out.println("授权--hasRoles--判断有给定角色中的哪些:"+flags[i]);
            }
            
            
            /**
             * hasRole 方法没有权限会返回false,不会抛异常,checkRole方法会抛异常
             * 检查权限,没有相应角色会抛异常UnauthorizedException
             */
            
            //检查一个权限
            subject.checkRole("role2");
            /**
             * 检查多个权限
             * 参数类型:1,可变参数String... ,2, Collection<String> 
             */
            subject.checkRoles("role1","role2");
            subject.checkRoles(Arrays.asList("role1","role2"));
            
            //****************基于【资源】的授权 *********************
            
            //isPermitted:判断单个权限:
            boolean permitted = subject.isPermitted("user:add");
            System.out.println("基于资源的权限--subject是否有-user:add权限-"+permitted);
            /**
             * isPermitted:判断是否有多个角色中的某些
             * 参数类型:String... 可变参数
             * 返回:boolean[] 
             */
            flags = subject.isPermitted("user:add","user:update","user:read");
            for (int i = 0; i < flags.length; i++) {
                System.out.println(flags[i]);
            }
            
            /**
             * isPermittedAll:判断是否有给定的【全部权限】
             * 参数类型:String... permissions可变参数
             * 返回:boolean
             */
            flag = subject.isPermittedAll("user:add","user:update");
            System.out.println(flag);
            
            /**
             * 判断一个权限,会抛异常UnauthorizedException
             */
            subject.checkPermission("user:read");
            /**
             * 判断多个权限:checkPermissions
             * 参数类型:String... permissions
             */
            subject.checkPermissions("user:add","user:update");
             
            //7 退出
            subject.logout();   
        
            
        }
    }

     shiro中的权限检查有三种方式:

    a)编程式:

            if(subject.hasRole("管理员")){   
                //操作某个资源
            }

    b)注解式:

      @RequiresRoles("管理员")
        public void list(){
            //查询数据
        }

    c) 标签式:

    <shiro:hasPermission name="user:update">
              <a href="#">更新</a>
          </shiro>

    授权流程:

    查看subject.isPermitted 源代码:

    其实调用的是DelegatingSubject类的isPermitted,DelegatingSubject 又交给了securityManager

    ctrl+t,查看类关系,可知,securityManager是SecurityManager接口的实现类DefaultSecurityManager,而DefaultSecurityManager类继承了好多个父类

    具体的是DefaultSecurityManager的父类 AuthorizingSecurityManager里有个Authorizer,

    其具体调用的是ModularRealmAuthorizer 的方法,最终交给了realm

    ModularRealmAuthorizer中有一个PermissionResolver,ctro+t 查看该Realm:它其实调用的是AuthorizingRealm,

    而AuthorizingRealm里,有PermissionResolver,而实际调用的是其实现类 WildcardPermissionResolver

    查看WildcardPermission:里边出现了熟悉的字符:就是来解析 shiro的权限的字符的。

    总结:

    a) 获取subject主体

    b)判断主题是否通过认证

    c)调用subject.isPermitted*/hasRole*进行授权的判断

      i)subject是由其实现类DelegatingSubject 来调用方法的,该类将处理交给了SecurityManager。

      ii)securityManager 是由其实现类 DefaultSecurityManager 来进行处理的,该类的isPermitted 来处理,其本质是父类AuthorizingSecurityManager来处理的。该类将处理交给了authorizer(授权器)

      iii)Authorizer 由其实现类 ModularRealmAuthorizer 来处理,该类可以调用对应的Realm来获取数据,在该类有PermissionResolver 对权限字符串进行解析,在对应的Realm中也有对应的 PermissionResolver 交给 WildcardPermissionResolver 该类调用WildPermission 来进行权限字符串的解析。

       iv) 返回处理结果

  • 相关阅读:
    Luogu P2633 Count on a tree
    Luogu P4011 孤岛营救问题
    Luogu P3157 [CQOI2011]动态逆序对
    SCOI2015 国旗计划
    AT2165 Median Pyramid Hard
    BZOJ2959 长跑
    SCOI2015 情报传递
    SDOI2011 染色
    SCOI2010 幸运数字
    SHOI2016 黑暗前的幻想乡
  • 原文地址:https://www.cnblogs.com/lihaoyang/p/6659874.html
Copyright © 2020-2023  润新知