• Shiro学习笔记(四):Shiro中的授权


    一、授权介绍

    1、授权

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

    对于授权可以理解为谁对哪些资源进行什么操作,授权中的关键对象如下:

    • 主体:主体需要访问系统中的资源
    • 资源:如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为g01的商品则称为资源实例,订单编号为o01的订单也为资源实例。
    • 权限/许可:规定了主体对资源的操作许可,如:用户查询权限、用户添加权限、某个类方法的调用权限、对编号为g01的商品的修改权限等,通过权限可知道主体对哪些资源具有哪些操作权限。

    2、授权流程

    3、授权方式

    • 基于角色的访问控制RBAC(Role-Based Access Control)是以角色为中心进行访问控制
    • 基于资源的访问控制RBAC(Resource-Based Access Control)是以资源为中心进行访问控制

    示例如下:

    //基于角色的访问控制
    if(subject.hasRole("admin")){
        //操作资源
    }
    //基于资源的角色控制
    if(subject.isPermission("user:update:01")){
        //拥有对01用户的修改权限
    }
    if(subject.isPermission("user:update:*")){
        //拥有对所有用户的修改权限
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4、权限字符串

    权限字符串是以字符串的方式实现对授权规则的表示,其规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,:是资源/操作1/实例的分隔符,权限字符串也可以使用*作为通配符。示例如下:

    用户创建权限:user:create,或user::create:*
    用户修改实例为001的权限:user:update:001
    用户拥有实例001的所有权限:user:*:001
    
    • 1
    • 2
    • 3

    5、shiro中授权编程实现方式

    (1)编程式

    Subject subject = SecurityUtils.getSubject();
    if(subject.hasRole("admin")){
        //有权限
    }else{
        //无权限
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2)注解式

    @RequiresRoles("admin")
    public void hello(){
        //有权限
    }
    
    • 1
    • 2
    • 3
    • 4

    (3)标签式

    
    
    
    • 1
    • 2

    二、Shiro实现授权示例

    1、角色验证

    方法说明如下:

    方法名

    说明

    hasRole

    是否具有某个角色

    hasAllRole

    是否具有所有角色

    hasRoles

    分别具有哪些角色

    代码:

    package org.example.shiro;
    
    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.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.crypto.hash.Md5Hash;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.subject.Subject;
    
    import java.util.Arrays;
    
    public class TestMD5 {
    //    21232f297a57a5a743894a0e4a801fc3
    //    a5599b5184c1aadc0877cd76cb93a969
    //    578422679b493529e22c5495c8b3db3c
        public static void main(String[] args) {
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            //注入realm
            UserMD5Realm realm = new UserMD5Realm();
            //设置realm使用hash凭证匹配器
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            credentialsMatcher.setHashAlgorithmName("md5");
            //设置散列次数
            credentialsMatcher.setHashIterations(1024);
            realm.setCredentialsMatcher(credentialsMatcher);
            //设置Realm
            defaultSecurityManager.setRealm(realm);
            //将安装工具类中设置默认安全管理器
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            //获取主体对象
            Subject subject = SecurityUtils.getSubject();
            //创建token令牌
            UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin");
            try{
                //用户登录
                subject.login(token);
                System.out.println("登陆成功");
            }catch (UnknownAccountException e){
                e.printStackTrace();
                System.out.println("用户名错误");
            }catch (IncorrectCredentialsException e){
                e.printStackTrace();
                System.out.println("密码错误");
            }
            //认证成功
            if(subject.isAuthenticated()){
                System.out.println(subject.hasRole("拥有的角色"));
                //hasRole判断是否具有某种角色
                System.out.println("hasRole方法");
                if(subject.hasRole("admin")){
                    System.out.println("admin拥有管理员角色");
                }else{
                    System.out.println("admin没有管理员角色");
                }
                //hasAllRoles判断是否同时具有这些角色
                System.out.println("hasAllRoles方法");
                if(subject.hasAllRoles(Arrays.asList("admin", "super", "users"))){
                    System.out.println("admin拥有管理员、超级管理员和用户角色");
                }else{
                    System.out.println("admin不同时具有这些角色");
                }
                //hasRoles是否具有其中一个角色
                System.out.println("hasRoles方法");
                boolean[] roles = subject.hasRoles(Arrays.asList("admin", "super", "users"));
                for(boolean b : roles){
                    System.out.println(b);
                }
            }
        }
    }
    
    
    package org.example.shiro;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    
    public class UserMD5Realm extends AuthorizingRealm {
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
            //根据身份信息 用户名获取当前用户的角色信息和权限信息,这一块从数据库中读取。
            //本案例中,我们假设admin用户具有管理员权限和普通用户的角色
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addRole("admin");
            simpleAuthorizationInfo.addRole("users");
            return simpleAuthorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //获取身份信息
            String principal = (String) authenticationToken.getPrincipal();
            if("admin".equals(principal)){
                //这里的密码模拟是从数据库中读到的
                String password = "578422679b493529e22c5495c8b3db3c";
                return new SimpleAuthenticationInfo(principal, password, ByteSource.Util.bytes("vasdg"), this.getName());
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    2、基于权限字符串的访问控制

    方法说明如下:

    方法名

    说明

    isPermitted

    是否具有某个权限

    isPermitted

    是否具有其中部分角色,前一个方法的重载

    isPermittedAll

    是否具有所有角色

    代码:

    基于上述代码加入以下逻辑:

    TestMD5的主方法

    //具有某种权限
                System.out.println("是否具有对01用户的修改权限 : " + subject.isPermitted("user:update:01"));
                //分别具有哪些权限
                boolean[] permitted01 = subject.isPermitted("user:*:01", "order:update:01");
                for(boolean b : permitted01){
                    System.out.println(b);
                }
                //同时具有哪些权限
                boolean permitted02 = subject.isPermittedAll("user:*:01", "order:update:01");
                System.out.println(permitted02);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    UserMD5Realm的doGetAuthorizationInfo()方法:

            //基于权限字符串的访问控制
            simpleAuthorizationInfo.addStringPermission("user:*:01");
            simpleAuthorizationInfo.addStringPermission("product:create:01");
    
    • 1
    • 2
    • 3
  • 相关阅读:
    四十九、openlayers官网示例Immediate Rendering (Geographic)——在地图上绘制星空动画效果
    NetSuite知识会 第7谈 项目如何保证按时上线
    Git(3)——Git的三大区域
    【前端必会】不知道webpack插件? webpack插件源码分析BannerPlugin
    海思3559万能平台搭建:添加一个新的sensor
    ArcGIS Pro创建、发布、调用GP服务全过程示例(等高线分析)
    白嫖免费版gpt与wetab插件的使用
    品质主管的面试题目
    前端面试:DOM检测两个div块是否碰撞
    基于Java的Android计算器设计与实现
  • 原文地址:https://blog.csdn.net/m0_67402731/article/details/126496323