Shiro中的授权

Shiro的授权

1. 授权

​ 授权,即访问控制。主体通过身份认证之后,需要分配权限。

2. 关键对象

  • Who
    • 主体,即主体需要访问系统中的资源
  • What
    • 即资源,如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。
  • How
    • 权限/许可,规定主体对资源的操作访问,权限离开资源乜有意义,如用户查询权限,用户添加权限。通过权限可以知道主体对哪些资源有哪些操作许可。

3. 授权流程

在这里插入图片描述

4. 授权方式

  • 基于角色的访问控制

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

    • 举例:

      if (subject.hasRole("admin")){
      	// 操作什么资源
      }
      
  • 基于资源的访问控制

    • RBAC基于资源的访问控制(Resource-Based Access Control)以资源为中心进行访问控制
    • 举例:
      if (subject.isPerssion("user:update:01")){
      	// 对01用户进行修改
      }
      
  • 权限字符串

    • 格式:资源标识符:操作:资源实例标识符
    • 标识对哪个资源的哪个实例具有什么操作
    • *为通配符
    • 举例
      • 用户创建权限: user:create, 或者 user:create:*
      • 用户修改实例001的权限: user:update:001
      • 用户筛查001的所有权限: user:*:001

5. 授权编码实现方式

  • 编程实现

    Subject subject = SecurityUtils.getSubject();
    if (subject.hasRole("admin")){
    	// 有权限,进行相应的操作
    }
    
  • 注解实现

    @RequiresRoles("admin")
    public void hello(){
    	// 有权限,进行相应的操作
    }
    
  • 标签实现

    JSP/GSP 标签:在JSP/GSP页面通过相应的标签完成
    <shiro:hasRole name="admin">
    	<!- 有权限 ->
    </shiro:hasRole>
    注意:Thymeleaf 中使用shiro需要额外集成
    

6. 代码实现

自定义Realm类

/**
 * @Author: Hjx
 * @Date: 2021/8/9 18:03
 */
public class CustomerMd5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        /*
            PrincipalCollection 身份的集合
            一个主体可以有多个身份,但是只有一个主身份
         */
        // 获取主体的主身份
        String principal = (String) principals.getPrimaryPrincipal();
        System.out.println("主身份信息"+principal);

        // 模拟根据用户的身份信息 从数据库中查询其角色信息
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("user");

        // 模拟从数据库查询权限信息,赋值给某个对象
        simpleAuthorizationInfo.addStringPermission("user:*:01");
        simpleAuthorizationInfo.addStringPermission("product:create:01");

        return simpleAuthorizationInfo;
    }


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 从 token 中获取用户输入的身份凭证
        String userName = (String) token.getPrincipal();
        // 模拟从数据库查询出的用户名和密码
        String name = "hjx";
        String pass = "1a0f1aac48cf23ffb080673fd60b5d2d";
        String credentialsSalt = "hjx";

        if (name.equals(userName)){
            /*
                SimpleAuthenticationInfo 是 AuthenticationInfo 的实现类
                参数1:用户名
                参数2:md5加密后的密码
                参数3:盐值,类型为ByteSource,需要进行格式转换
                参数4:自定义realm的名称
             */
            return new SimpleAuthenticationInfo(name, pass, ByteSource.Util.bytes(credentialsSalt), this.getName());
        }
        return null;
    }
}

Test测试类

/**
 * @Author: Hjx
 * @Date: 2021/8/9 17:57
 */
public class TestMd5Authenticator {
    public static void main(String[] args) {
        // 创建SecurityManager安全管理器
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();

        // 给SecurityManager设置自定义Realm
        CustomerMd5Realm customerMd5Realm = new CustomerMd5Realm();

        // 设置md5 凭证适配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 设置加密方式
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 设置散列次数
        hashedCredentialsMatcher.setHashIterations(1024);
        customerMd5Realm.setCredentialsMatcher(hashedCredentialsMatcher);

        defaultSecurityManager.setRealm(customerMd5Realm);
        // 给安全工具类SecurityUtils 设置 SecurityManager
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        // 通过安全工具类SecurityUtils获取 主体subject
        Subject subject = SecurityUtils.getSubject();
        // 创建Token,模拟接收前端用户输入的用户名和密码
        UsernamePasswordToken token = new UsernamePasswordToken("hjx", "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("密码错误");
        }catch (Exception e){
            e.printStackTrace();
        }

        // 对通过身份认证的是用户进行授权管理
        if (subject.isAuthenticated()){

            // 基于角色的访问控制
            if (subject.hasRole("admin")){
                System.out.println("该用户拥有 admin 的权限");
            }else {
                System.out.println("该用户没有 admin 的权限");
            }

            // 基于多角色的访问控制
            if(subject.hasAllRoles(Arrays.asList("admin","user"))){
                System.out.println("该用户拥有 admin user 的权限");
            }

            // 具有其中一个角色
            boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user", "super"));
            for (boolean bool:booleans){
                System.out.println(bool);
            }
            System.out.println("================================================");
            // 基于全新字符串的权限控制
            System.out.println(subject.isPermitted("user:*:01"));

            // 分别具有哪些权限
            boolean[] booleans1 = subject.isPermitted("user:*:01", "product:update:01");
            for (boolean bool:booleans1){
                System.out.println(bool);
            }

            // 同时具有哪些权限
            System.out.println(subject.isPermittedAll("user:*:01", "product:*"));
        }

    }
}

代码及资料地址:hjx: 知道的越多,越发觉自己的无知 (gitee.com)
视频学习参考:【编程不良人】2020最新版Shiro教程,整合SpringBoot项目实战教程_哔哩哔哩_bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值