Shiro学习(一):Shiro介绍和基本使用
一、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 内存实现,适用于快速原型开发
或测试场景。它直接在内存储存用户、角色和权限信息,无需连接数据库或外部配置。
示例代码如下:
@Testpublic void authen(){/*** 认证需要准备3个角色* 1)认证得发起者(一般叫Subject)* 2)SecurityManager* 3)Realm* 认证发起者得能够找到 SecurityManager,SecurityManager得能够找到 Realm,所以这三者需要存在依赖关系** 认证流程如下:*///1、准备 RealmSimpleAccountRealm realm = new SimpleAccountRealm();//添加用户//模拟拿到用户信息:用户名称、密码、角色信息realm.addAccount("admin","123456","超级管理员","商家");//2、准备 SecurityManagerDefaultSecurityManager securityManager = new DefaultSecurityManager();//3、SecurityManager 与 Realm 建立连接securityManager.setRealm(realm);//4、Subject 与 SecurityManager 建立链接SecurityUtils.setSecurityManager(securityManager);//5、准备 SubjectSubject 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 文件内容如下:

示例代码如下:
@Testpublic void authen(){//1、构建 RealmIniRealm realm = new IniRealm("classpath:shiro.ini");//2、构建 SecurityManager 并绑定RealmDefaultSecurityManager securityManager = new DefaultSecurityManager();securityManager.setRealm(realm);//3、基于 SecurityUtils 绑定 SecurityManager 并声明认证主题(即认证发起者)SubjectSecurityUtils.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的认证授权需要连接
数据库,示例代码如下:
@Testpublic void authen(){//1、构建RealmJdbcRealm 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,并绑定RealmDefaultSecurityManager securityManager = new DefaultSecurityManager();securityManager.setRealm(realm);//3、并基于SecurityUtil 绑定SecurityManager,并声明主题(认证者)SubjectSecurityUtils.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*/@Overrideprotected 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*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//1、获取用户名称String userName = (String) token.getPrincipal();//2、判断用户名称是否为空if(StringUtils.isEmpty(userName)){// 返回null,会默认抛出一个异常,org.apache.shiro.authc.UnknownAccountExceptionreturn 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;
}
相关文章:
Shiro学习(一):Shiro介绍和基本使用
一、Shiro介绍 1、百科对shiro的定义如下: Apache Shiro 一个强大且易于使用的 Java 安全框架,它提供了身份验证、授权、加密和会话管理等功能。Shiro 的设计目标是简化企业级应用程序的安全性开发过程,同时保持代码的简洁和易于维护。 2、…...
【git】基本操作
添加文件进本地仓库 git add 文件名删除文件 git rm 文件名版本回退 git reset [--sort| -- mixed | -- hard] sort选项: 只回退版本库,不回退暂存区和工作区 mixed(reset的默认选项): 回退版本库和暂存区,不回退工作区 hard :…...
7.1 分治-快排专题:LeetCode 75. 颜色分类
1. 题目链接 LeetCode 75. 颜色分类 2. 题目描述 给定一个包含红色(0)、白色(1)和蓝色(2)的数组 nums,要求原地对数组进行排序,使得相同颜色的元素相邻,且按红、白、蓝…...
深度解析:TOML、XML、YAML及其他配置/数据格式对比
深度解析:TOML、XML、YAML及其他配置/数据格式对比 在软件开发和系统配置中,选择合适的配置或数据格式至关重要。本文将对比 TOML、XML、YAML 等常见格式,梳理它们的核心特性、适用场景及区别,并扩展介绍其他类似格式,…...
开源软件许可证冲突的原因和解决方法
1、什么是开源许可证以及许可证冲突产生的问题 开源软件许可证是一种法律文件,它规定了软件用户、分发者和修改者使用、复制、修改和分发开源软件的权利和义务。开源许可证是由软件的版权所有者(通常是开发者或开发团队)发布的,它…...
详解java体系实用知识总结
0.java技术能力框架 基础模块应用模块综合模块技术岗位与面试流程常用工具集系统架构设计计算机基础常用框架微服务架构jvm原理缓存容器化多线程队列云计算(阿里云/aws)设计模式数据库数据结构与算法 1.常用设计模式与应用场景 工厂模式:s…...
node-ddk,electron,主进程通讯,窗口间通讯
node-ddk,electron,主进程通讯,窗口间通讯 https://blog.csdn.net/eli960/article/details/146207062 也可以下载demo直接演示 http://linuxmail.cn/go#node-ddk import 在主进程 import main, { NODEDDK } from "node-ddk/main"在渲染进程 import renderer, …...
kubectl 命令参数详解与示例
kubectl 命令参数详解与示例 kubectl 是 Kubernetes 的命令行工具,用于与 Kubernetes 集群交互。下面我将详细介绍 kubectl 的主要命令参数,并提供相应的使用示例。 一、基础命令 1. kubectl get - 获取资源信息 常用参数: -n, --namesp…...
在 Ubuntu 20.04 上重新启动网络
参考链接: 如何在 Ubuntu 22.04 上重新启动网络 执行以下两条命令,ok sudo nmcli networking off sudo nmcli networking on...
STM32 - 在机器人、自动化领域,LL库相比HAL优势明显
在机器人控制器、电机控制器等领域的开发,需要高实时性、精细化控制或者对代码执行效率、占用空间有较高要求。所以,大家常用的HAL库明显不符合要求。再加上,我们学习一门技术,一定要学会掌握底层的原理。MCU开发的底层就是寄存器…...
【区块链安全 | 第二篇】区块链概念详解
文章目录 概述1. 区块链类型2 区块链五层架构3 账本模型4. 节点(Node)5. 区块(Block)6. 区块链(Blockchain)7. 区块链工作流程 核心技术1. 共识机制2. 智能合约 主要组件1. 交易(Transaction&am…...
【开源宝藏】30天学会CSS - DAY6 第六课 流光文字动画
第 0 步:项目结构 lighting-text/├─ index.html└─ style.cssindex.html:包含列表 <ul>,其中每个 <li> 放一个字母或符号。style.css:设置背景、文字样式,以及关键帧动画(lighting…...
linux - centos7 部署 redis6.0.5
事先说明 本篇文章只解决在部署redis中出现的问题,并没有部署redis的全过程,详细部署过程可以参考Linux安装部署Redis(超级详细) - 长沙大鹏 - 博客园 执行 make 命令时报错 原因:是因为gcc版本太低 升级gcc版本时 出现没有可用软件包 devt…...
Java反射机制详解:原理、应用与最佳实践
Java反射机制详解:原理、应用与最佳实践 1. 什么是反射? Java反射(Reflection)是指在运行时动态获取类的信息(如类名、方法、字段、构造方法等)并操作对象的能力。它允许程序在运行时检查和修改类的行为&…...
Swift实现嵌套json字典重排序并输出string
在网络请求或接口签名中,通常要求将参数按照一定规则拼接成字符串。一个常见的做法是对字典的 key 进行排序,然后按照 “keyvalue” 的格式拼接,多个参数之间以特定符号(例如 &)连接。 如果参数中包含嵌套的字典或…...
【Ai】--- 可视化 DeepSeek-r1 接入 Open WebUI(超详细)
在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。【Ai】--- 可视化 DeepSeek-r1 接入 Open WebUI(超详细) 开发环境一、前情提要:你…...
VSCode加Cline插件加DeepSeek实现AI编程指南
VSCode加Cline插件加DeepSeek实现AI编程指南 简介 本文将详细介绍如何在VSCode中使用Cline插件结合DeepSeek AI实现高效的AI辅助编程,特别适合初学者快速上手。我们将通过实现一个TodoList应用的例子来演示整个流程。 环境准备 1. 安装VSCode 前往VSCode官网下…...
代码规范之Variable Names变量名
代码规范之Variable Names变量名 golang中 官方文档:https://go.dev/wiki/CodeReviewComments#variable-names Variable names in Go should be short rather than long. This is especially true for local variables with limited scope. Prefer c to lineCoun…...
2025春招市场迎AI热潮:生成式人工智能(GAI)认证如何重构人才竞争力
随着科技的飞速发展,人工智能(AI)已逐渐渗透到我们生活的方方面面,从智能家居到自动驾驶,从智能客服到医疗诊断,AI的身影无处不在。而在这股AI浪潮中,生成式人工智能(Generative AI,…...
Flink基础简介和安装部署
文章目录 一、Flink基础简介1、什么是Flink2、Flink流处理特性3、Flink四大基石4、Flink中的角色 二、Flink集群搭建1、Local模式①上传Flink安装包②启动交互窗口③提交任务测试④访问WebUI页面查看⑤退出停止集群 2、Standalone模式①修改配置⽂件 conf/flink-conf.yaml②修改…...
SpringBoot分布式项目实战:观察者模式的高阶应用与避坑指南
一、痛点场景:当观察者遇上分布式 在某电商平台重构项目中,我们遭遇了这样的困境:订单中心完成支付后需要触发库存扣减、积分结算、物流调度等12个后续操作。最初的实现采用了硬编码调用: // 伪代码示例 public void paySuccess…...
How to use pgbench to test performance for PostgreSQL?
pgbench 是一个用于测试 PostgreSQL 数据库性能的基准测试工具。通过模拟多个客户端并发执行 SQL 查询,它可以帮助你评估数据库的性能。以下是使用 pgbench 的基本步骤: 安装 pgbench pgbench 是 PostgreSQL 的一部分,因此在安装 PostgreSQ…...
C#基础学习(五)函数中的ref和out
1. 引言:为什么需要ref和out? 问题背景:函数参数默认按值传递,值类型在函数内修改不影响外部变量;引用类型重新赋值时外部对象不变。核心作用:允许函数内部修改外部变量的值,实现“双向传参…...
从零构建大语言模型全栈开发指南:第二部分:模型架构设计与实现-2.2.2文本生成逻辑:Top-k采样与温度控制
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 2.2.2 文本生成逻辑:Top-k采样与温度控制1. 文本生成的核心挑战与数学框架1.1 自回归生成的基本流程2. `Top-k`采样原理与工程实现2.1 数学定义与算法流程2.2 PyTorch实现优化3. 温度控制的数学本质与参…...
关于CodeJava的学习笔记——9
一、IO流 1、定义 IInput输入 OOutput输出 流 : 数据从源点传输到汇点的"管道"而已 2、流的分类 按照方向分: 输入流 输出流 *:参照物当前Java程序为参照物 按照单位分: 字节流 字符流 按照功能分: 节点流 过滤流(包装流 处…...
LeetCode算法题(Go语言实现)_11
题目 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"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体…...
Day38 | 1365. 有多少小于当前数字的数字、941. 有效的山脉数组、1207. 独一无二的出现次数、283. 移动零、189. 轮转数组
1365. 有多少小于当前数字的数字 题目链接:1365. 有多少小、于当前数字的数字 - 力扣(LeetCode) 题目难度:简单 代码: class Solution {public int[] smallerNumbersThanCurrent(int[] nums) {Map<Integer,Inte…...
Docker-清理容器空间prune
docker system prune -a 是一个非常有用的命令,用于清理 Docker 系统中未使用的资源,包括停止的容器、未使用的网络、卷以及未被任何容器引用的镜像(悬空镜像和所有未使用的镜像)。以下是关于该命令的详细说明: 命令格…...
matplotlib——南丁格尔玫瑰
南丁格尔玫瑰图(Nightingale Rose Chart),是一种特殊形式的柱状图,它以南丁格尔(Florence Nightingale)命名,她在1858年首次使用这种图表来展示战争期间士兵死亡原因的数据。 它将数据绘制在极坐…...
