zoukankan      html  css  js  c++  java
  • Shiro 授权流程详解

    1. 授权

      授权即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。

    2. 关键对象

      授权可简单理解为 who 对 what(which)进行 How 操作;

      Who,即主体(Subject),主体需要访问系统中的资源;

      What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为 t01 的商品为资源实例,编号 001 的商品也属于资源实例;

      How,权限 / 许可(Permission),规定了主体对资源的操作许可, 权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为 001 用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。

    3. 授权流程

         

    4. 授权方式

    • 基于角色的访问控制【RBAC 基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制】
    if(subject.hasRole("admin")){
       //操作什么资源
    }
    • 基于资源的访问控制【RBAC 基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制】
    if(subject.isPermission("user:update:01")){ //资源实例
      //对01用户进行修改
    }
    if(subject.isPermission("user:update:*")){  //资源类型
      //对01用户进行修改
    }

    5. 权限字符串

      权限字符串的规则是【资源标识符:操作:资源实例标识符】意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用 * 通配符。

    例子:

    • 用户创建权限:user : create,或 user : create : *

    • 用户修改实例001的权限:user : update : 001

    • 用户实例001的所有权限:user : *:001

    6. 开发授权代码

      a 自定义 Realm 代码实现

    public class CustomerMD5Realm extends AuthorizingRealm {
    
        /**
         * 一个主题可以有多个身份,参数是集合 principals;但是只有一个主身份;
         * @param principals
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            // 获取身份信息
            String principal = (String) principals.getPrimaryPrincipal();
            System.out.println("身份信息 = " + principal);
    
            // 根据身份信息 用户名 获取当前用户的角色信息,以及权限信息【比如:从数据库中获取】
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            // 将数据库中查询角色信息赋值给权限对象
            simpleAuthorizationInfo.addRoles(Arrays.asList("admin", "user"));
            simpleAuthorizationInfo.addStringPermission("user:*:01");
            simpleAuthorizationInfo.addStringPermission("product:*:*");
            return simpleAuthorizationInfo;
        }
    
        // 认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            String principal = (String) token.getPrincipal();
            System.out.println("principal = " + principal);
            return null;
        }
    }

      b 授权处理【会自动调用自定义 CustomerMD5Realm 的 doGetAuthorizationInfo 获取指定用户的权限信息】

    public class TestCustomerMD5Authenticator {
    
        public static void main(String[] args) {
            // 1. 创建安全管理器
            DefaultSecurityManager securityManager = new DefaultSecurityManager();
    
            // 2. 给安全管理器设置 realm 【Realm 需要获取用户认证的数据源信息】
            CustomerMD5Realm customerMD5Realm = new CustomerMD5Realm();
            // 设置 realm 使用的 hash 凭证匹配器
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            credentialsMatcher.setHashAlgorithmName("md5"); // 设置使用的 Hash 算法
            credentialsMatcher.setHashIterations(1024);     // 需要散列多少次
            customerMD5Realm.setCredentialsMatcher(credentialsMatcher);
            securityManager.setRealm(customerMD5Realm);
    
            // 3. SecurityUtils 设置安全管理器
            SecurityUtils.setSecurityManager(securityManager);
    
            // 4. 获取关键对象 Subject 主体
            Subject subject = SecurityUtils.getSubject();
    
            // 5. 创建令牌
            UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");
    
            // 用户认证
            try {
                System.out.println("认证状态: " + subject.isAuthenticated());
                subject.login(token);
                System.out.println("认证状态: " + subject.isAuthenticated());
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                System.out.println("认证失败: 用户名不存在~");
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
                System.out.println("认证失败: 密码错误~");
            }
    
            // 授权
            if (subject.isAuthenticated()) {
                //基于角色权限控制
                System.out.println(subject.hasRole("super"));  // 走授权流程
    
                // 基于多角色权限控制
                System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));  // 走授权流程
    
                // 是否具有其中一个角色
                boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user", "super"));  // 走授权流程
                for (boolean aBoolean : booleans) {
                    System.out.println(aBoolean);
                }
    
                // 基于权限字符串的访问控制 资源标识符:操作:资源类型
                System.out.println(subject.isPermitted("user:update:01"));  // 走授权流程
    
                // 分别具有哪些权限
                boolean[] permitted = subject.isPermitted("user:*:01", "order:*:02");  // 走授权流程
                for (boolean b : permitted) {
                    System.out.println(b);
                }
            }
        }
    
    }

      注意:深入了解 Shiro 的授权流程,可以 debug 运行程序,查看源代码进行学习深究!

  • 相关阅读:
    Python print() 函数
    Python issubclass() 函数
    Python execfile() 函数
    Python basestring() 函数
    QTP自动化测试-点滴-步骤
    qtp自动化测试-条件语句 if select case
    学习心态--笔记
    测试计划小记
    QTP自动化测试-笔记 注释、大小写
    win10 新建文件夹没有了
  • 原文地址:https://www.cnblogs.com/blogtech/p/14823020.html
Copyright © 2011-2022 走看看