Shiro基础学习篇01

Shiro

  • 权限管理框架包含: 认证授权

认证

  • 各种登录方式统称为认证,包含(用户名密码,门禁卡,指纹,刷脸等等)

    主体

    • 用户信息,列如账户信息

    身份信息

    • 主体进行认证登录时的表示,必须唯一。列如用户名,身份证号,人脸…

    凭证信息

    • 只有主体知道的安全信息,密码,证书…等

授权

  • 访问控制,主体信息通过认证后分配给哪些权限可以访问。

  • 将系统中的资源分配给用户主体的过程。用户每次访问系统都进行拦截认证–>授权检查。

    资源

    • 系统中提供可访问的菜单或功能服务。

    权限

    • 一个用户主体可能访问哪些资源,分配的权限。

权限管理的解决方案

URL拦截器自定义判断

  • 通过springmvc的AOP进行权限判断,自己手动封装。不常用

  • web服务的权限拦截通过 URL请求路径进行判断拦截。

  • 在这里插入图片描述

权限框架Shiro

  • 节省系统开发时间,框架提供了完善的 认证授权 的相关操作。
  • 例如: Shiro 和 springSecurity

Shiro简介

  • Shiro是 apache 下一个开源安全管理框架。
  • 将安全认证相关功能提取封装,实现用户身份认证,权限授权,加密,会话管理等功能。
  • Shiro可以运行在web应用和非web应用,集群分布式应用中也同样适用。

Subject主体

  • Subject 是 shiro 的一个接口,接口中定义了很多认证授权相关的方法,Subkect通过 SecurityManager 安全管理器进行认证授权。

SecurityManager安全管理器-主要核心服务

  • SecurityManager :安全管理器,是 shiro 的核心。
  • 负责对所有的 Subject 进行安全管理。完成对 Subject认证授权 等操作。
  • SecurityManager
    • 通过 Authenticator 进行认证。
    • 通过 Authorize 进行授权。
    • 通过 SessionManager 进行会话管理等。
  • SecurityManager 是一个接口,继承了 AuthenticatorAuthorizeSessionManager 三个接口。

Authenticator 认证器

  • 对主体 Subject 进行认证登录操作。

Authorize 授权器

  • 用户通过 认证器后,在访问功能/菜单/接口时,判断用户是否此功能的操作权限。

Realm 权限存储

  • SecurityManager 进行安全认证需要通过 Realm 获取用户的权限数据。
  • Realm 从数据库存储中获取到用户的权限信息
  • Realm 也是一个接口,有多种实现。
    1. 将用户的权限信息写在配置文件 ini配置文件
    2. 将用户的全选信息存储到数据库(RBAC模式)
  • 就是配置shiro用户权限的信息数据接口

SessionManger会话管理

  • SessionManager 会话管理器。
  • shiro 自己定义的一套会话管理,并非web服务的session,并不依赖web服务容器session。
  • shiro 可以使用在非web应用上,可以将分布式应用的会话集中在一点管理,可实现单点登录。

SessionDao会话操作

  • 对shiro 会话操作的一套接口,可以将用户的会话信息进行自定义扩展操作,比如存储到redis中。

CacheManager缓存管理

  • 用于对shiro中的session、realm中的认证信息、授权信息进行缓存 ,提供系统性能。

Cryptography密码管理器

  • shrio提供了一套加密/解密的组件,进行明文密码的加密操作,进行散列算法的加密操作,存储在数据库中。

Shiro基本格式

maven依赖

  • <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.4.0</version>
    </dependency>
    

语法格式

  • 不集成spring则需要在 resource 下创建一个shiro.ini的配置文件,进行认证和授权的信息配置。

  • # users代表用户信息, zhangsan-账号, 123456-密码, admin-角色
    [users]
    zhangsan=123456,admin
    lisi=456789,public
    
    # 角色资源分配 product-菜单功能 view-查询 ****等操作权限
    [roles]
    admin=product:view,product:create,product:update,product:delete
    

简单代码示例

  • 通过shiroSecurityManager 安全管理器进行 ini 认证授权信息文件的加载和处理。

  • shiro.ini 配置文件

  • [users]
    zhangsan=123,admin
    
    [roles]
    admin=product:view,product:create,product:update,product:delete
    
  • @Slf4j
    public class ShiroTest01 {
        @Test
        public void run() {
            // 1. 创建shiro的 SecurityManager 核心安全管理器
            DefaultSecurityManager securityManager = new DefaultSecurityManager();
    
            // 2. 设置用户的权限信息,从shiro.ini配置文件中读取
            IniRealm realm = new IniRealm("classpath:shiro.ini");
            securityManager.setRealm(realm);
    
            // 3. 赋值安全管理器给shiro工具类,设置shiro的运行环境中
            SecurityUtils.setSecurityManager(securityManager);
    
            // 4.创建一个subject主体实例
            Subject subject = SecurityUtils.getSubject();
    
            // 5. 创建登录校验的用户名和密码token
            UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","123");
    
            // 6. 进行用户登录 , 通过主体进行 Authenticator认证 和 Authorize授权
            try {
                subject.login(token);
            } catch (IncorrectCredentialsException e) {
                log.error("用户密码错误===>" , e);
            } catch (AuthenticationException e) {
                log.error("系统错误===>" , e);
            }
    
            // 7. 打印登录情况
            log.info("是否登录===>{}" , subject.isAuthenticated());
            log.info("登录信息===>{}" , subject.getPrincipal());
    
            // 8. 权限校验
            log.info("是否有权限===>{}" , subject.isPermitted("product:view","product:list"));
            log.info("是否拥有某角色信息===>{}" , subject.hasRole("admin"));
    
            // 9. 登出系统
            subject.logout();
    
            // 10. 查看是否登出
            log.info("是否登录===>{}" , subject.isAuthenticated());
        }
    }
    

基础总结

  1. Shiro是以前在学校当做课外学习的内容,但工作之后已经有两三年没有再碰过了,而2021今年开始要好好充电学习,先拿Shiro开刀。
  2. 在工作中项目也是用到shiro来权限管理,功能还是十分的实用。一般工作中都是把用户权限等信息储存在数据库中,在shiro初始化配置时读取数据库,来配置角色和权限。
  3. 本节第一节只是日常学习笔记记录,示例代码也是最简单最基础的单元测试类。

Shiro基础扩展功能

自定义Realm

  • Realm 用于存储 用户的认证和权限 等相关信息,在正常业务中一般这些信息都存储在数据库中,所以我们需要自定义实现 Realm 从数据库中获取用户的认证授权信息,进行自定义处理。

  • Realm 主要继承 AuthorizingRealm 来实现自定义操作。

  • AuthorizingRealm(权限) 继承于 AuthenticatingRealm(认证) 继承于 CachingRealm 实现缓存管理,三者父子继承关系,一般继承 AuthorizingRealm 来进行自定义处理。

  • 代码示例:

  • @Slf4j
    public class ShiroRealmConfiguration extends AuthorizingRealm {
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            // 自定义登录验证方法
            log.info("自定义Realm验证用户信息=========>");
            // 1. token转为 usernameAndPasswordToken 获取用户信息
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            // 2. 获取用户信息,进而去数据库中校验用户
            String username = token.getUsername();
            char[] password = token.getPassword();
            if (!"zhangsan".equals(username)) {
                throw new UnknownAccountException();
            }
            System.out.println(token.getPrincipal());
            System.out.println(token.getCredentials());
    
            // 3. 进行密码校验,加密的密码直接通过 SimpleAuthenticationInfo 可以内部进行校验密码
            return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),username);
        }
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            // 自定义权限授权方法
            log.info("自定义Realm验证权限=========>");
            // 1. 获取主体信息,此信息由认证SimpleAuthenticationInfo 第一个参数配置的对象
            String userName = (String) principalCollection.getPrimaryPrincipal();
            if ("zhangsan".equals(userName)) {
                // 2. 配置各类信息
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                info.setRoles(Collections.singleton("admin")); // 赋值多角色
                // 多权限字符串
                Set<String> permissionSet = new HashSet<String>();
                permissionSet.add("product:view");
                permissionSet.add("product:create");
                info.setStringPermissions(permissionSet);
                return info;
            }
            return null;
        }
    }
    

Shiro异常类

  • Shiro提供了一系列自定义的异常类信息,用于在业务中判断用户密码错误,用户信息不存在等异常情况。
  • 在这里插入图片描述

密码加密

散列算法

  • 散列算法一般用于生成文本的散列摘要信息,而无法再逆转为原始明文内容。

    • 散列算法不可逆
    • 散列算法常用于对密码的加密
    • 常用散列算法主要用 MD5 和 SHA
  • 一般散列算法需要提供一个 salt(盐) 与 原始明文生成摘要信息,为了更加安全。

  • // 列如
    密码 123456 通过 MD5 散列加密成 abc 通过MD5解密网站就可以解密成明文原始
    加上 salt(盐,一个随机数) 则可以生成不同的摘要信息,更加安全
        
    SimpleHash hash01 = new SimpleHash("MD5", "123456", "AK");
    log.info("Shiro进行MD5散列加密===>{}" , hash01);
    
    // hashIterations参数表示 散列迭代次数,类似递归方法重复散列计算
    Md5Hash hash02 = new Md5Hash("123456", "AK" , 2);
    log.info("Shiro进行MD5散列加密,并且散列两次===>{}" , hash02);
    
    // 盐值用原文密码,通过Shiro转换盐值的方法
    ByteSource salt = ByteSource.Util.bytes("123456");
    log.info("通过Shiro的方法获取盐值===>{}",salt.toString());
    

密码比较

  • 一般存储在数据库中用户密码都是 MD5加密后,不可逆的摘要信息存储。

  • 将数据库输入的密码进行同样的加密处理后,与数据库密文密码进行比较来判断。

  • // 在自定义继承 AuthorizingRealm 的 realm 中进行密码的判断
    @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            // 自定义登录验证方法
            // ******************************
    
            // 3. 进行密码校验,加密的密码直接通过 SimpleAuthenticationInfo 可以内部进行校验密码
    return new SimpleAuthenticationInfo(token.getPrincipal(),"ea48576f30be1669971699c09ad05c94", ByteSource.Util.bytes(token.getPassword()),"user");
        }
    
    // 将MD5加密后的密文 和 之前所用的salt ,Shiro自动进行密码校验
    

缓存管理

  • 没有缓存,shiro每次调用判断是否权限,都会走 RealmdoGetAuthorizationInfo 权限校验的方法。

  • Shiro默认是关闭缓存管理器的,需要配置赋值给 SecurityManager 核心安全管理器

  • 缓存之前:

  • 在这里插入图片描述

  • 缓存之后

  • 在这里插入图片描述

内置缓存管理器

  • Shiro有内置自己的缓存管理器 CacheManager

  • 创建 MemoryConstrainedCacheManager() 实现类对象即可

  • // 设置缓存管理器, 赋值给 SecurityManager 核心管理器
    CacheManager cacheManager = new MemoryConstrainedCacheManager();
    securityManager.setCacheManager(cacheManager);
    

第三方缓存支持

  • Shiro的内置缓存管理器,性能低扩展性差,有时我们需要第三方的Cache缓存管理器。

  • 比如常用的Redis缓存

  • <!-- shiro-redis 单机方法 -->
    <dependency>
    	<groupId>org.crazycake</groupId>
        <artifactId>shiro-redis</artifactId>
        <version>3.3.1</version>
    </dependency>
    
    <!-- springboot中使用 -->
    <dependency>
       <groupId>org.crazycake</groupId>
       <artifactId>shiro-redis-spring-boot-starter</artifactId>
       <version>3.3.1</version>
    </dependency>
    
  • 代码示例

  • RedisCacheManager redisCacheManager = new RedisCacheManager();
    redisCacheManager.setRedisManager(new RedisManager());
    securityManager.setCacheManager(redisCacheManager);
    

权限数据模型

  • RABC 权限模型设计。数据库表相关的模型设计。
  • 用户 —> 多个角色 —> 多个权限。 最少需要五张表来构建权限模型结构。

资源表设计

  • 模型中最复杂的是资源表,企业中的一套资源表设计。

    • url: 请求的后端路径,后端通过访问路径来判断需要的不同角色进行校验。
    • route:前端路由,前端通过路由来判断是否隐藏。
    • level:表示级别
      • 1: 表示一级菜单
      • 2: 表示二级菜单
      • 3:依次类推(类似新增,修改等按钮视为最后一级菜单)
    • type:表示是菜单页面还是按钮
  • CREATE TABLE `sys_menu_info` (
      `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
      `parent_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '上级资源ID',
      `url` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'url',
      `router` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '前端路径',
      `title` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '资源名称',
      `level` int DEFAULT NULL COMMENT '资源级别1-一级菜单,2-二级菜单,3-三级菜单',
      `sort_no` int DEFAULT NULL COMMENT '排序',
      `type` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '类型 0-菜单,1-按钮(table,button)',
      `status` int NOT NULL DEFAULT '1' COMMENT '状态0-无效,1-有效',
      `remark` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
      `create_time` datetime NOT NULL COMMENT '创建时间',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=277 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-权限资源表 ';
    
  • 数据结构:

  • 在这里插入图片描述

Realm接口架构图

  • 在这里插入图片描述

Shiro整体结构图

  • Shiro整体结构图

  • 在这里插入图片描述

  • Subject: 主体相当于与客户端交互的用户信息
    
    SecurityManager: Shiro的核心管理器,管理者Shiro的一切,认证授权会话缓存.等
    
    Authenticator: 认证器,负责主体Subject的认证登录操作
    
    Authorizer: 授权器,负责主体Subject的权限相关验证
    
    Realm: 可以有多个Realm,是Shiro的安全认证数据源,可以自定义从数据库获取
    
    SessionManager: 会话管理器,管理者Session的生命周期,Session是客户端与服务端交互的关联信息,集群模式下可以使用Redis作为分布式会话管理
    
    SessionDao: 用来操作Session会话的CRUD,向SessionManager负责,可以自定义实现存储到数据库或者redis中。
    
    CacheManager: 缓存管理器,管理比如用户,角色,权限等缓存。可以提高系统的性能。
    
    Cryptography: 密码模块,提供的一些常见的加密组件
    
  • ShiroSecurityManager管理者所有的Subject(登录信息) , Realm是认证安全数据源

  • 在这里插入图片描述

项目文件 shiro-test01

  • 链接:https://pan.baidu.com/s/1OotLAOubzxpZDpPLpjdFuw
    提取码:bk3p
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值