Shiro学习(一):Shiro介绍和基本使用

news2025/4/1 19:26:07

一、Shiro介绍

1、百科对shiro的定义如下:

Apache Shiro 一个强大且易于使用的 Java 安全框架,它提供了身份验证、授权、加密和会话管理等功能。Shiro 的设计目标是简化企业级应用程序的安全性开发过程,同时保持代码的简洁和易于维护。

2、Shiro 核心功能介绍

2.1、Authentication(认证)

        认证和授权是Shiro最核心的功能,认证操作主要用来处理2方便的工作,即:

             1)验证用户身份,如:用户名密码、OAuth、LDAP等。

                  LDAP(轻量级目录访问协议)种在互联网上标准的数据协议,用于访问和维护分布式

                  目录信息服务。在许多企业和组织中,LDAP被用来存储用户认证信息,如用户名、密

                  码、电子邮件地址等,用于实现LDAP统一用户认证和单点登录

             2)支持多 Realm(数据源),如数据库、LDAP、Active Directory 等。

2.2、Authorization(授权)

       授权主要用来做 :

       1)基于角色(Role)和权限(Permission)的资源控制访问

       2)支持细粒度的权限控制,如:user:create、file:edit等

2.3、Session Management(会话管理)

        会话管理主要用来做:

         1)提供会话管理,即使没有 Web 容器(如 Tomcat)也能使用。

         2)支持分布式会话,如:Redis缓存。

2.4、Cryptography(加密)

       1)Shiro加密模块提供哈希(如 MD5、SHA)、加解密(AES、DES)等工具。

       2)Shiro支持密码加盐(Salt)和多次哈希迭代

2.5、Web Integration(Web集成)

       1)提供 ShiroFilter 拦截请求,实现 URL 级别的安全控制

       2)支持 RESTful API 安全认证(如 JWT 集成)

2.6、Cache(缓存)

       1)Shiro 支持缓存认证和授权信息,提高性能(如 Redis、Ehcache)。

3、Shiro 核心角色和架构:

3.1、Shiro 核心架构图如下:

        

3.2、Shiro 核心角色如下:

       1)Subject

            表示当前“用户”,Subject 用户并不是单单指登录程序的user;与程序交互的任何主体都是

            Subject用户,如:网络爬虫、user、机器设备等等。

            所有的Subject 用户都由 SecurityManager管理,Subject由当前线程绑定(通过

            ThreadLocal实现),即Subject 是线程安全的;

            Shiro 是所有安全操作的入口;在开发中通常通过Shiro的工具类SecurityUtils.getSubject()

            来获取Subject,如下图所示:

                  

       2)SecurityManager

             SecurityManager 是Shrio 的核心,管理所有的安全操作,协调所有安全组件,

              如:认证、授权、会话管理。

             在Shiro 中 SecurityManager 的重要实现有2个,即:

                  1)DefaultSecurityManager    默认实现

                  2)SessionsSecurityManager  支持会话管理

       3)Authenticator

            认证器,用于Subject用户的认证逻辑;

            Shiro 默认实现是 ModularRealmAuthenticator

            认证流程:

               (1)用户提交凭证(如 UsernamePasswordToken)。

               (2)Authenticator 调用 Realm 的 doGetAuthenticationInfo() 方法。

               (3)匹配凭证与 Realm 返回的数据(如密码加盐哈希比较)。

       4)Authorizer

             授权器,用于判断认证通过的用户是否具有某些资源的访问权限的过程;

             Shiro 支持基于角色和权限的资源访问控制。

             Shiro 的默认实现是 ModularRealmAuthorizer

       5)SessionManager

             管理Session 生命周期的组件,是Shiro 自带的session会话管理器,这就表示即使在非

             Web环境中也可以使用Shiro进行认证和授权。

             Shiro中 SessionManager 的核心实现如下:

                  (1)DefaultSessionManager(默认实现)

                  (2)ServletContainerSessionManager(委托给 Servlet 容器,如 Tomcat)

                  (3)EnterpriseCacheSessionManager(支持分布式缓存,如 Redis)

       

       6)CacheManager

              该组件用于缓存认证、授权、角色、会话等的数据,提升性能。

              Shiro中默认的实现有:

                 (1)MemoryConstrainedCacheManager(内存缓存)

                 (2)EhCacheManager(集成 Ehcache)

                 (3)RedisCacheManager(将数据缓存到Redis,分布式缓存)

       7)Realm 

            Realm,安全数据源, 是连接Shiro 与 安全数据的桥梁(如:JDBC数据库数据、LADP、

            内存数据);用于获取安全数据进行认证、授权;

            Realm 可以有多个,由用户自己提供;一般应用中需要用户定义自己的Realm;

            Shiro默认提供了3个Realm 实现,即:

                   1)IniRealm:基于 .ini文件的配置,从Shiro.ini读取用户 认证/授权 和 角色数据

                   2)JdbcRealm:通过JDBC查询数据库中的安全数据(认证/授权 相关的数据)

                   3)TextConfigurationRealm:安全数据配置在内存中,用于替代 IniRealm

       8)Filter

           Web过滤器,在 Web 环境中拦截请求,实现 URL 级别的安全控制

二、Shiro 简单使用

下边分别以 SimpleAccountRealm、IniRealm、JdbcRealm、自定义Realm 分别来演示下Shiro

认证和授权的基本流程。

     1)认证流程

            

     2)授权流程

           

1、SimpleAccountRealm

      SimpleAccountRealm是Shiro 提供的一个最基本的 Realm 内存实现,适用于快速原型开发

       或测试场景。它直接在内存储存用户、角色和权限信息,无需连接数据库或外部配置。

      示例代码如下:

@Test
    public void authen(){

        /**
         * 认证需要准备3个角色
         * 1)认证得发起者(一般叫Subject)
         * 2)SecurityManager
         * 3)Realm
         * 认证发起者得能够找到 SecurityManager,SecurityManager得能够找到 Realm,所以这三者需要存在依赖关系
         *
         * 认证流程如下:
         */
        //1、准备 Realm
        SimpleAccountRealm realm = new SimpleAccountRealm();
        //添加用户
        //模拟拿到用户信息:用户名称、密码、角色信息
        realm.addAccount("admin","123456","超级管理员","商家");

        //2、准备 SecurityManager
        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        //3、SecurityManager 与 Realm 建立连接
        securityManager.setRealm(realm);

        //4、Subject 与 SecurityManager 建立链接
        SecurityUtils.setSecurityManager(securityManager);

        //5、准备 Subject
        Subject subject = SecurityUtils.getSubject();

        //6、发起认证,认证失败抛出异常 AuthenticationException,认证通过不抛出异常
        subject.login(new UsernamePasswordToken("admin","123456"));

        //7、判断是否认证成功
        System.out.println(subject.isAuthenticated());

        //8、判断用户角色
        boolean b1 = subject.hasRole("超级管理员");//判断是否有超级管理员角色
        //使用 checkRole/checkRoles判断角色时,若角色不存在,则会抛出异常AuthorizationException
        
        // SimpleAccountRealm只支持角色的授权
        System.out.println("是否拥有超级管理员角色:" +b1);
        subject.checkRole("商家");

        //9、退出校验
        subject.logout();
    }

2、IniRealm

      IniRealm 是基于文件存储的授权认证,IniRealm 可以将用户的用户名、密码、角色信息存储

      到.ini文件中,来实现持久化;所示使用IniRealm 需要先准备一个.ini文件,如:Shiro.ini;

     Shiro.ini 文件内容如下:

           

      示例代码如下:

@Test
    public void authen(){

        //1、构建 Realm
        IniRealm realm = new IniRealm("classpath:shiro.ini");

        //2、构建 SecurityManager 并绑定Realm
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        securityManager.setRealm(realm);

        //3、基于 SecurityUtils 绑定 SecurityManager 并声明认证主题(即认证发起者)Subject
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();

        //4、执行认证操作
        subject.login(new UsernamePasswordToken("admin","123456"));

        //5、角色校验
        boolean b1 = subject.hasRole("超级管理员");//判断是否有超级管理员角色
        System.out.println(b1);

        //6、权限校验
        //权限校验失败会抛出异常
        subject.checkPermission("user:add");
        subject.checkPermission("user:select");

    }

3、JdbcRealm

     JdbcRealm 是把认证授权的数据保存到数据库中,所以基于JdbcRealm的认证授权需要连接

     数据库,示例代码如下:

    

@Test
    public void authen(){

        //1、构建Realm
        JdbcRealm realm = new JdbcRealm();
        //设置数据源
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://47.100.7.152:3306/shiro");
        dataSource.setUsername("javademo");
        dataSource.setPassword("123qwe!@#");
        realm.setDataSource(dataSource);

        //开启权限校验,JdbcRealm 默认是不能进行权限校验的
        realm.setPermissionsLookupEnabled(true);

        /**
         * JdbcRealm 自定义 认证查询、权限查询、角色查询sql
         */
        //认证查询sql
        //realm.setAuthenticationQuery(sql);
        //权限查询sql
        //realm.setPermissionsQuery(sql);
        //角色查询sql
        //realm.setUserRolesQuery(sql);

        //2、构建 SecurityManager,并绑定Realm
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        securityManager.setRealm(realm);

        //3、并基于SecurityUtil 绑定SecurityManager,并声明主题(认证者)Subject
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();

        //4、执行认证操作
        subject.login(new UsernamePasswordToken("admin","123456"));

        //5. 授权操作(角色)
        System.out.println(subject.hasRole("超级管1理员"));

        //6. 授权操作(权限)
        System.out.println(subject.isPermitted("user:add"));
    }

4、CustomRealm

      CustomRealm是一个自定义的Realm;

      自定义Realm 一般需要继承 AuthorizingRealm 并重写方法doGetAuthenticationInfo(授权)与

      方法doGetAuthenticationInfo(认证)

     示例代码如下:

/****************************************************
 * 模拟JdbcRealm 自定义 Realm(即 CustomRealm) 来完成认证和授权
 * 自定义 CustomRealm 需要继承 AuthorizingRealm 并实现 AuthorizingRealm 的2个
 * 核心方法:doGetAuthorizationInfo 和 doGetAuthenticationInfo
 *
 * @author lbf
 * @date 
 ****************************************************/
public class CustomRealm extends AuthorizingRealm {

    /**
     * 授权
     * todo 注意:
     *    授权是在认证之后的操作,授权方法需要用到认证方法返回的 AuthenticationInfo  中的用户信息
     *
     * @param principals  即 doGetAuthenticationInfo 方法返回的 AuthenticationInfo 中的用户信息(这里是User )
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //1. 获取认证用户的信息
        User user = (User) principals.getPrimaryPrincipal();

        //2. 基于用户信息获取当前用户拥有的角色。
        Set<String> roleSet = this.findRolesByUser();

        //3. 基于用户拥有的角色查询权限信息
        Set<String> permSet = this.findPermsByRoleSet(roleSet);

        //4. 声明AuthorizationInfo对象作为返回值,传入角色信息和权限信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roleSet);
        info.setStringPermissions(permSet);

        //5. 返回
        return info;
    }

    private Set<String> findPermsByRoleSet(Set<String> roleSet) {
        Set<String> set = new HashSet<>();
        set.add("user:add");
        set.add("user:update");
        return set;
    }

    private Set<String> findRolesByUser() {
        Set<String> set = new HashSet<>();
        set.add("超级管理员");
        set.add("运营");
        return set;
    }

    /**
     * 认证 用户执行认证操作传入的用户名和密码
     * 只需要完成用户名校验即可,密码校验由Shiro内部完成
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1、获取用户名称
        String userName = (String) token.getPrincipal();

        //2、判断用户名称是否为空
        if(StringUtils.isEmpty(userName)){
            // 返回null,会默认抛出一个异常,org.apache.shiro.authc.UnknownAccountException
            return null;
        }
        //4、如果用户名称不为空,则基于用户名称去查询用户信息
        //这一步一般是自己的UserService 服务
        //模拟查询用户信息
        User user = this.findUserByUsername(userName);
        if(user == null){
            return null;
        }

        //5、构建 AuthenticationInfo 对象,并填充用户信息
        /**
         * todo 注意:
         *    SimpleAuthenticationInfo 第一个参数是用户信息,第二个参数是用户密码,第三个参数是Realm名称(这个参数没有意义)
         */
        SimpleAuthenticationInfo info =  new SimpleAuthenticationInfo(user,user.getPassword(),"CustomRealm!!!");

        //返回 AuthenticationInfo 对象
        return info;
    }

    // 模拟数据库操作
    private User findUserByUsername(String username) {
        if("admin".equals(username)){
            User user = new User();
            user.setId(1);
            user.setUsername("admin");
            user.setPassword("admin");
            return user;
        }
        return null;
    }
}



public class User {

    private Integer id;

    private String username;

    private String password;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7.1 分治-快排专题:LeetCode 75. 颜色分类

1. 题目链接 LeetCode 75. 颜色分类 2. 题目描述 给定一个包含红色&#xff08;0&#xff09;、白色&#xff08;1&#xff09;和蓝色&#xff08;2&#xff09;的数组 nums&#xff0c;要求原地对数组进行排序&#xff0c;使得相同颜色的元素相邻&#xff0c;且按红、白、蓝…

开源软件许可证冲突的原因和解决方法

1、什么是开源许可证以及许可证冲突产生的问题 开源软件许可证是一种法律文件&#xff0c;它规定了软件用户、分发者和修改者使用、复制、修改和分发开源软件的权利和义务。开源许可证是由软件的版权所有者&#xff08;通常是开发者或开发团队&#xff09;发布的&#xff0c;它…

详解java体系实用知识总结

0.java技术能力框架 基础模块应用模块综合模块技术岗位与面试流程常用工具集系统架构设计计算机基础常用框架微服务架构jvm原理缓存容器化多线程队列云计算&#xff08;阿里云/aws&#xff09;设计模式数据库数据结构与算法 1.常用设计模式与应用场景 工厂模式&#xff1a;s…

【区块链安全 | 第二篇】区块链概念详解

文章目录 概述1. 区块链类型2 区块链五层架构3 账本模型4. 节点&#xff08;Node&#xff09;5. 区块&#xff08;Block&#xff09;6. 区块链&#xff08;Blockchain&#xff09;7. 区块链工作流程 核心技术1. 共识机制2. 智能合约 主要组件1. 交易&#xff08;Transaction&am…

【开源宝藏】30天学会CSS - DAY6 第六课 流光文字动画

第 0 步&#xff1a;项目结构 lighting-text/├─ index.html└─ style.cssindex.html&#xff1a;包含列表 <ul>&#xff0c;其中每个 <li> 放一个字母或符号。style.css&#xff1a;设置背景、文字样式&#xff0c;以及关键帧动画&#xff08;lighting&#xf…

Swift实现嵌套json字典重排序并输出string

在网络请求或接口签名中&#xff0c;通常要求将参数按照一定规则拼接成字符串。一个常见的做法是对字典的 key 进行排序&#xff0c;然后按照 “keyvalue” 的格式拼接&#xff0c;多个参数之间以特定符号&#xff08;例如 &&#xff09;连接。 如果参数中包含嵌套的字典或…

【Ai】--- 可视化 DeepSeek-r1 接入 Open WebUI(超详细)

在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。【Ai】--- 可视化 DeepSeek-r1 接入 Open WebUI(超详细) 开发环境一、前情提要:你…

Flink基础简介和安装部署

文章目录 一、Flink基础简介1、什么是Flink2、Flink流处理特性3、Flink四大基石4、Flink中的角色 二、Flink集群搭建1、Local模式①上传Flink安装包②启动交互窗口③提交任务测试④访问WebUI页面查看⑤退出停止集群 2、Standalone模式①修改配置⽂件 conf/flink-conf.yaml②修改…

从零构建大语言模型全栈开发指南:第二部分:模型架构设计与实现-2.2.2文本生成逻辑:Top-k采样与温度控制

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 2.2.2 文本生成逻辑:Top-k采样与温度控制1. 文本生成的核心挑战与数学框架1.1 自回归生成的基本流程2. `Top-k`采样原理与工程实现2.1 数学定义与算法流程2.2 PyTorch实现优化3. 温度控制的数学本质与参…

LeetCode算法题(Go语言实现)_11

题目 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"abcde"的一个子序列&a…

Python----数据分析(足球运动员数据分析)

一、数据展示 1.1、数据 1.2、列名 字段名备注Name姓名Nationality国籍National_Position国家队位置National_Kit国家队号码Club所在俱乐部Club_Position所在俱乐部位置Club_Kit俱乐部号码Club_Joining加入俱乐部时间Contract_Expiry合同到期时间Rating评分Height身高Weight体…

matplotlib——南丁格尔玫瑰

南丁格尔玫瑰图&#xff08;Nightingale Rose Chart&#xff09;&#xff0c;是一种特殊形式的柱状图&#xff0c;它以南丁格尔&#xff08;Florence Nightingale&#xff09;命名&#xff0c;她在1858年首次使用这种图表来展示战争期间士兵死亡原因的数据。 它将数据绘制在极坐…

Django与网页表单

我叫补三补四&#xff0c;很高兴见到大家&#xff0c;欢迎一起学习交流和进步 今天来讲一讲网页表单 网页表单又叫做HTML表单&#xff0c;用来处理用户从页面输入发送到服务器的数据&#xff0c;页面表单通常会提供复选框、单选按钮和文本字段&#xff0c;方便用户填写各种形式…

ChatDBA VS DeepSeek:快速诊断 OceanBase 集群新租户数据同步异常

社区王牌专栏《一问一实验&#xff1a;AI 版》改版以来已发布多期&#xff08;51-60&#xff09;&#xff0c;展现了 ChatDBA 在多种场景下解决问题的效果。 下面让我们正式进入《一问一实验&#xff1a;AI 版》第 62 期&#xff0c;看看 ChatDBA 最新效果以及与热门大模型 De…

Python----计算机视觉处理(Opencv:图像边缘检测:非极大值抑制,双阈值筛选)

一、 高斯滤波 边缘检测本身属于锐化操作&#xff0c;对噪点比较敏感&#xff0c;所以需要进行平滑处理。这里使用的是一个5*5的高斯 核对图像进行消除噪声。 二、计算图像的梯度和方向 三、非极大值抑制 在得到每个边缘的方向之后&#xff0c;其实把它们连起来边缘检测就算完了…

基于Kubernetes部署Prometheus监控平台

#作者&#xff1a;stackofumbrella 文章目录 prometheus和k8s集群版本对照表架构Prometheus Operator简介kube-prometheus下载地址 安装修改镜像地址修改Prometheus的service修改Grafana的service修改Alertmanager的service数据持久化执行安装 Prometheus验证Grafana验证解决C…

往期项目shader着色器实践效果应用合集

1、管路混色 2、水管水流效果 3、水管流入到流完效果 4、加热冷却 两 色混色 示意 XX、毒蘑菇测试效果

绿色暴政:Relax Max如何用军工科技定义环保新标准

《绿色暴政&#xff1a;Relax Max如何用军工科技定义环保新标准》 ——从隐形战斗机涂层到零碳卫浴的降维打击 &#xff08;洛克希德马丁实验室&#xff0c;2023年&#xff09;当F-35战斗机的隐形涂料配方被改写为卫浴釉料时&#xff0c;环保产业迎来了最硬核的颠覆者。Relax…

第十三届蓝桥杯单片机省赛程序设计试题

目录 试题 各程序块代码 init.c main.c other.h other.c key.c seg.c onewire.c部分 ds1302.c部分 试题 各程序块代码 init.c #include "other.h"void init74hc138(unsigned char n){P2(P2&0x1f)|(n<<5);P2&0x1f; } void init(){P00x00;in…

QOpenGLWidget动态加载功能实现教程(Qt+OpenGL)

QOpenGLWidget动态加载功能实现教程 我需要在Qt里面使用QOpenGLWidget显示OpenGL窗口&#xff0c;并且需要实现加载模型后重新渲染更新窗口的功能&#xff0c;但是一直无法更新被卡住了&#xff0c;现在把问题解决了总结一下整个实现过程。 创建一个自己的OpenGLWidget类 QOp…