使用 Shiro 和 JPA 结合 MySQL 实现一个简易权限管理系统
1. 项目设置
首先,确保你的项目已经配置好 Maven 或 Gradle 依赖管理工具,并添加以下依赖:
Maven 依赖
<dependencies><!-- Shiro 核心库 --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.9.0</version></dependency><!-- Shiro Web 支持 --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>1.9.0</version></dependency><!-- JPA 支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- MySQL 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version></dependency><!-- Spring Boot Web 支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot 安全支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- 其他依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
</dependencies>
2. 配置 MySQL 数据库
在 application.properties 或 application.yml 中配置 MySQL 数据库连接:
spring.datasource.url=jdbc:mysql://localhost:3306/shiro_demo
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
3. 创建实体类
使用 JPA 创建用户、角色和权限的实体类。
用户实体 (User)
@Entity
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String username;private String password;@ManyToMany(fetch = FetchType.EAGER)private Set<Role> roles;// Getters and Setters
}
角色实体 (Role)
@Entity
public class Role {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;@ManyToMany(fetch = FetchType.EAGER)private Set<Permission> permissions;// Getters and Setters
}
权限实体 (Permission)
@Entity
public class Permission {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;// Getters and Setters
}
4. 创建 Repository 接口
使用 Spring Data JPA 创建 Repository 接口。
public interface UserRepository extends JpaRepository<User, Long> {User findByUsername(String username);
}public interface RoleRepository extends JpaRepository<Role, Long> {
}public interface PermissionRepository extends JpaRepository<Permission, Long> {
}
5. 配置 Shiro
创建一个 Shiro 配置类,配置 Realm 和 SecurityManager。
@Configuration
public class ShiroConfig {@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();filterChainDefinitionMap.put("/login", "anon");filterChainDefinitionMap.put("/logout", "logout");filterChainDefinitionMap.put("/**", "authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}@Beanpublic SecurityManager securityManager(Realm realm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(realm);return securityManager;}@Beanpublic Realm realm(UserRepository userRepository) {return new JpaRealm(userRepository);}
}
6. 自定义 Realm
创建一个自定义的 Realm 类,用于从数据库中获取用户信息。
public class JpaRealm extends AuthorizingRealm {private final UserRepository userRepository;public JpaRealm(UserRepository userRepository) {this.userRepository = userRepository;}@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String username = (String) principals.getPrimaryPrincipal();User user = userRepository.findByUsername(username);SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();for (Role role : user.getRoles()) {authorizationInfo.addRole(role.getName());for (Permission permission : role.getPermissions()) {authorizationInfo.addStringPermission(permission.getName());}}return authorizationInfo;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String username = (String) token.getPrincipal();User user = userRepository.findByUsername(username);if (user == null) {throw new UnknownAccountException("User not found");}return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());}
}
7. 创建控制器
创建一个简单的控制器来处理登录和访问控制。
@Controller
public class HomeController {@GetMapping("/home")public String home() {return "home";}@GetMapping("/login")public String login() {return "login";}@PostMapping("/login")public String doLogin(@RequestParam String username, @RequestParam String password) {Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password);try {subject.login(token);return "redirect:/home";} catch (AuthenticationException e) {return "redirect:/login?error";}}@GetMapping("/logout")public String logout() {Subject subject = SecurityUtils.getSubject();subject.logout();return "redirect:/login";}
}
8. 创建视图
创建简单的 Thymeleaf 视图来展示登录页面和主页。
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Login</title>
</head>
<body><h1>Login</h1><form th:action="@{/login}" method="post"><label for="username">Username:</label><input type="text" id="username" name="username" required><br><label for="password">Password:</label><input type="password" id="password" name="password" required><br><button type="submit">Login</button></form><p th:if="${param.error}" style="color: red;">Invalid username or password</p>
</body>
</html>
运行 HTML
home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Home</title>
</head>
<body><h1>Welcome to the Home Page</h1><a th:href="@{/logout}">Logout</a>
</body>
</html>
9. 运行项目
启动 Spring Boot 应用程序,访问 http://localhost:8080/login 进行登录。登录成功后,你将能够访问 /home 页面。
10. 权限控制
你可以在控制器中使用 @RequiresRoles 或 @RequiresPermissions 注解来控制访问权限。
@Controller
public class AdminController {@RequiresRoles("admin")@GetMapping("/admin")public String admin() {return "admin";}
}
11、创建测试数据脚本
-- 插入权限数据
INSERT INTO permission (name) VALUES ('user:read');
INSERT INTO permission (name) VALUES ('user:write');
INSERT INTO permission (name) VALUES ('admin:read');
INSERT INTO permission (name) VALUES ('admin:write');-- 插入角色数据
INSERT INTO role (name) VALUES ('user');
INSERT INTO role (name) VALUES ('admin');-- 关联角色和权限
-- 用户角色拥有 user:read 和 user:write 权限
INSERT INTO role_permissions (role_id, permissions_id) VALUES ((SELECT id FROM role WHERE name = 'user'),(SELECT id FROM permission WHERE name = 'user:read')
);
INSERT INTO role_permissions (role_id, permissions_id) VALUES ((SELECT id FROM role WHERE name = 'user'),(SELECT id FROM permission WHERE name = 'user:write')
);-- 管理员角色拥有所有权限
INSERT INTO role_permissions (role_id, permissions_id) VALUES ((SELECT id FROM role WHERE name = 'admin'),(SELECT id FROM permission WHERE name = 'user:read')
);
INSERT INTO role_permissions (role_id, permissions_id) VALUES ((SELECT id FROM role WHERE name = 'admin'),(SELECT id FROM permission WHERE name = 'user:write')
);
INSERT INTO role_permissions (role_id, permissions_id) VALUES ((SELECT id FROM role WHERE name = 'admin'),(SELECT id FROM permission WHERE name = 'admin:read')
);
INSERT INTO role_permissions (role_id, permissions_id) VALUES ((SELECT id FROM role WHERE name = 'admin'),(SELECT id FROM permission WHERE name = 'admin:write')
);-- 插入用户数据
-- 密码使用 Shiro 的加密方式(例如 MD5 加密)
INSERT INTO user (username, password) VALUES ('user1', 'password1');
INSERT INTO user (username, password) VALUES ('admin1', 'password1');-- 关联用户和角色
-- 用户 user1 拥有 user 角色
INSERT INTO user_roles (user_id, roles_id) VALUES ((SELECT id FROM user WHERE username = 'user1'),(SELECT id FROM role WHERE name = 'user')
);-- 用户 admin1 拥有 admin 角色
INSERT INTO user_roles (user_id, roles_id) VALUES ((SELECT id FROM user WHERE username = 'admin1'),(SELECT id FROM role WHERE name = 'admin')
);
测试登录
启动应用程序后,使用以下测试用户登录:
-
用户:
user1,密码:password1,角色:user -
用户:
admin1,密码:password1,角色:admin
登录后,你可以根据角色和权限访问不同的页面。
相关文章:
使用 Shiro 和 JPA 结合 MySQL 实现一个简易权限管理系统
1. 项目设置 首先,确保你的项目已经配置好 Maven 或 Gradle 依赖管理工具,并添加以下依赖: Maven 依赖 <dependencies><!-- Shiro 核心库 --><dependency><groupId>org.apache.shiro</groupId><artifactI…...
DeepSeek与医院电子病历的深度融合路径:本地化和上云差异化分析
一、引言 1.1 研究背景与意义 在医疗信息化快速发展的当下,电子病历系统已成为医院信息管理的核心构成。电子病历(EMR)系统,是指医务人员在医疗活动过程中,使用医疗机构信息系统生成的文字、符号、图标、图形、数据、影像等数字化信息,并能实现存储、管理、传输和重现的…...
设计模式:代理模式
代理模式是很常见的设计模式,即使没有专门学习过这种设计模式,在工作中也一定用过这种设计模式。在实际生活中,代理模式也是常见的,比如内阁首辅相对于皇帝,前者是后者的代理,内阁首辅收到奏折时࿰…...
141,【1】buuctf web [SUCTF 2019]EasyWeb
进入靶场 代码审计 <?php // 定义函数get_the_flag,功能是处理文件上传相关操作 function get_the_flag() {// 注释说明:webadmin会每隔20分钟删除用户上传的文件$userdir "upload/tmp_" . md5($_SERVER[REMOTE_ADDR]);// 检查用户目录…...
破解微服务疑难杂症:2025年全解决方案
微服务架构已经成为现代软件开发的主流选择,其优势在于能够将复杂的系统拆分为独立的服务模块,方便开发和维护。然而,在微服务的实施过程中,开发者往往会面临许多挑战,如服务间通信、数据一致性、性能优化和故障处理等…...
Node.js 中的 Event 模块详解
Node.js 中的 Event 模块是实现事件驱动编程的核心模块。它基于观察者模式,允许对象(称为“事件发射器”)发布事件,而其他对象(称为“事件监听器”)可以订阅并响应这些事件。这种模式非常适合处理异步操作和…...
EasyRTC嵌入式WebRTC视频通话SDK支持Web浏览器、Linux、ARM、Android、iOS
随着互联网技术的飞速发展,实时通信(RTC)已经成为现代应用中不可或缺的一部分。无论是视频会议、在线教育、远程医疗,还是社交娱乐,实时通信技术都在其中扮演着重要角色。 然而,WebRTC技术在PC和移动端的支…...
pycharm社区版有个window和arm64版本,到底下载哪一个?还有pycharm官网
首先pycharm官网是这一个。我是在2025年2月16日9:57进入的网站。如果网站还没有更新的话,那么就往下滑一下找到 community Edition,这个就是社区版了免费的。PyCharm:适用于数据科学和 Web 开发的 Python IDE 适用于数据科学和 Web 开发的 Python IDE&am…...
【玩转全栈】----Django模板语法、请求与响应
目录 一、引言 二、模板语法 三、传参 1、视图函数到模板文件 2、模板文件到视图函数 四、引入静态文件 五、请求与响应 ?1、请求 2、响应 六、综合小案例 1、源码展示 2、注意事项以及部分解释 3、展示 一、引言 像之前那个页面,太过简陋,而且一个完整…...
网络安全:挑战、技术与未来发展
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 1. 引言 在数字化时代,网络安全(Cybersecurity)已成为全球关注的焦点。随着云计算、大数据、…...
DeepSeek 服务器繁忙的全面解决方案
目录 引文 正文 一、 服务器繁忙的原因分析 二、 解决方案 2.1切换网络 2.2使用网络加速工具 2.3错峰使用DeepSeek 2.4本地部署 2.5调用API 三、官方动态 一、技术研发与产品升级 二、市场合作与商业化进展 三、区域化布局与产业赋能 四、未来规划与社会责任 结语…...
将OpenWrt部署在x86服务器上
正文共:1234 字 40 图,预估阅读时间:2 分钟 如果你问ChatGPT有哪些开源的SD-WAN方案,他会这样答复你: 我们看到,OpenWrt也属于比较知名的开源SD-WAN解决方案。当然,在很久之前,我就发…...
计算机视觉:卷积神经网络(CNN)基本概念(一)
第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络 一、引言 卷积神经网络&…...
企业文件共享中的权限管理与安全风险防范
在企业的日常运营中,文件共享是必不可少的一项工作。然而,文件共享过程中如果权限管理不当,极易引发安全风险,导致企业敏感信息泄露。因此,加强文件共享中的权限管理与安全风险防范,对于保障企业信息安全至…...
使用DeepSeek建立一个智能聊天机器人0.12
为了确保这段代码能够在Windows和Linux系统上都能正常运行,我考虑以下几个方面: 路径分隔符:在Windows和Linux中,文件路径的分隔符不同。Windows使用反斜杠(\),而Linux使用正斜杠(/)。我们可以使用 os.path.join 来处理路径,以确保跨平台兼容性。 消息框:tkinter.…...
国家队出手!DeepSeek上线国家超算互联网平台!
目前,国家超算互联网平台已推出 DeepSeek – R1 模型的 1.5B、7B、8B、14B 版本,后续还会在近期更新 32B、70B 等版本。 DeepSeek太火爆了!在这个春节档,直接成了全民热议的话题。 DeepSeek也毫无悬念地干到了全球增速最快的AI应用。这几天,国内的云计算厂家都在支持Dee…...
Deep seek学习日记1
Deepseek最强大的就是它的深度思考,并且展现了它的思考过程。 五种可使用Deep seek的方式(应该不限于这五种,后续嵌入deepseek的应该更多,多了解一点因为官网容易崩~~): 1.deep seek官网 2.硅基流动silicon…...
乐理笔记(持续更新)
单音与音程 单音:由一个音组成。 音程:由两个音组成,表示两个音之间的音高距离。 如何数音程: 单音程:9 - X,性质相反。例如,9度音程减去某个数,性质会相反。 复音程:…...
【动态路由】系统Web URL资源整合系列(后端技术实现)【nodejs实现】
需求说明 软件功能需求:反向代理功能(描述:apollo、eureka控、apisix、sentinel、普米、kibana、timetask、grafana、hbase、skywalking-ui、pinpoint、cmak界面、kafka-map、nacos、gateway、elasticsearch、 oa-portal 业务应用等多个web资…...
PHP高效、轻量级表格数据处理库 OpenSpout ,很好用
OpenSpout 是一个高效、轻量级的 PHP 库,用于处理电子表格文件(如 Excel 和 CSV)。它支持读取和写入大型文件,且内存占用低。本文将详细介绍如何安装和使用 OpenSpout。 目录 安装 基本使用 高级功能 参考文档 安装 OpenSp…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
