你的王牌特工霹雳椒娃已上线Spring Boot 2.x 整合 Apache Shiro 安全框架实战指南在日常企业级应用开发中权限控制与安全认证是每个后端开发者必须面对的核心问题。最近在重构一个内部管理系统时我深刻体会到选择合适的安全框架对项目稳定性的重要性。本文将基于 Spring Boot 2.x 整合 Apache Shiro手把手带你构建一个完整的权限管理系统涵盖从环境搭建到生产部署的全流程。无论你是刚接触安全框架的新手还是希望优化现有权限体系的进阶开发者本文提供的完整代码示例和避坑指南都能直接复用。我们将重点解决 Shiro 与 Spring Boot 的版本兼容性、动态权限管理、会话控制等实际开发中的高频问题。1. 安全框架背景与核心概念1.1 为什么需要权限控制框架在现代 Web 应用中不同用户需要访问不同的资源。比如普通员工只能查看个人信息而部门经理可以审批请假系统管理员则拥有全部权限。如果手动在每个接口编写权限判断逻辑不仅代码冗余还容易产生安全漏洞。Apache Shiro 是一个强大易用的 Java 安全框架提供了认证、授权、加密和会话管理等功能。与 Spring Security 相比Shiro 的 API 设计更加直观学习曲线平缓特别适合中小型项目的快速集成。1.2 Shiro 核心组件解析Shiro 架构围绕三个核心概念构建Subject主体代表当前执行操作的用户或程序是 Shiro 的核心交互对象。开发者通过 Subject 进行登录、权限验证等操作。SecurityManager安全管理器Shiro 的核心组件管理所有 Subject 的安全操作。它协调多个安全组件的工作相当于 Spring 的 ApplicationContext。Realm域Shiro 与应用安全数据用户、角色、权限的桥梁。开发者需要自定义 Realm 实现从数据库或其他数据源加载认证和授权信息。// Shiro 核心工作流程示例 Subject currentUser SecurityUtils.getSubject(); if (!currentUser.isAuthenticated()) { UsernamePasswordToken token new UsernamePasswordToken(username, password); currentUser.login(token); // 认证 } if (currentUser.hasRole(admin)) { // 授权 // 执行管理员操作 }2. 环境准备与版本说明2.1 技术栈与版本要求本次实战基于以下环境建议读者保持相同版本以避免兼容性问题JDK 版本1.8 或更高推荐 OpenJDK 11Spring Boot2.7.18长期支持版本Apache Shiro1.11.0与 Spring Boot 2.x 兼容性最佳数据库MySQL 8.0也可适配其他关系型数据库构建工具Maven 3.6IDEIntelliJ IDEA 或 Eclipse2.2 项目结构规划在开始编码前我们先规划清晰的项目结构shiro-demo/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── shirodemo/ │ │ │ ├── config/ # 配置类 │ │ │ ├── controller/ # 控制器 │ │ │ ├── entity/ # 实体类 │ │ │ ├── realm/ # 自定义 Realm │ │ │ ├── service/ # 业务层 │ │ │ └── ShiroDemoApplication.java │ │ └── resources/ │ │ ├── application.yml # 主配置文件 │ │ └── shiro-config.ini # Shiro 配置可选 │ └── test/ # 测试代码 ├── pom.xml # Maven 依赖 └── README.md3. 核心依赖与基础配置3.1 Maven 依赖配置在pom.xml中添加 Spring Boot 和 Shiro 相关依赖。特别注意版本兼容性错误版本组合会导致启动失败。?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent groupIdcom.example/groupId artifactIdshiro-demo/artifactId version1.0.0/version properties java.version11/java.version shiro.version1.11.0/shiro.version /properties dependencies !-- Spring Boot Web 支持 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring Boot Thymeleaf 模板可选用于演示页面 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency !-- Shiro 核心 -- dependency groupIdorg.apache.shiro/groupId artifactIdshiro-spring-boot-web-starter/artifactId version${shiro.version}/version /dependency !-- 数据库相关按需添加 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- 测试依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies /project3.2 应用配置文件在application.yml中配置数据库连接、Shiro 基本参数等server: port: 8080 servlet: context-path: /shiro-demo spring: datasource: url: jdbc:mysql://localhost:3306/shiro_demo?useSSLfalseserverTimezoneUTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update show-sql: true # Shiro 特定配置 shiro: enabled: true loginUrl: /login # 未认证时重定向地址 successUrl: /index # 登录成功默认跳转地址 unauthorizedUrl: /403 # 未授权访问跳转地址4. Shiro 核心配置类详解4.1 安全管理器配置创建ShiroConfig类这是整合 Spring Boot 与 Shiro 的核心配置package com.example.shirodemo.config; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; Configuration public class ShiroConfig { /** * 创建自定义 Realm */ Bean public CustomRealm customRealm() { return new CustomRealm(); } /** * 创建安全管理器并注入自定义 Realm */ Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager new DefaultWebSecurityManager(); securityManager.setRealm(customRealm()); return securityManager; } /** * Shiro 过滤器工厂定义URL拦截规则 */ Bean public ShiroFilterFactoryBean shiroFilterFactoryBean() { ShiroFilterFactoryBean factoryBean new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager()); // 设置登录页面 factoryBean.setLoginUrl(/login); // 登录成功后跳转页面 factoryBean.setSuccessUrl(/index); // 未授权页面 factoryBean.setUnauthorizedUrl(/403); // 定义过滤器链注意顺序很重要 MapString, String filterChainDefinitionMap new LinkedHashMap(); // 静态资源放行 filterChainDefinitionMap.put(/css/**, anon); filterChainDefinitionMap.put(/js/**, anon); filterChainDefinitionMap.put(/images/**, anon); // 登录相关接口放行 filterChainDefinitionMap.put(/login, anon); filterChainDefinitionMap.put(/doLogin, anon); // 需要认证的接口 filterChainDefinitionMap.put(/user/**, authc); filterChainDefinitionMap.put(/admin/**, authc,roles[admin]); // 其余接口需要登录访问 filterChainDefinitionMap.put(/**, authc); factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return factoryBean; } }4.2 自定义 Realm 实现Realm 是 Shiro 连接应用数据的桥梁我们需要实现认证和授权逻辑package com.example.shirodemo.realm; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.stereotype.Component; Component public class CustomRealm extends AuthorizingRealm { /** * 授权逻辑获取用户的角色和权限信息 */ Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username (String) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo new SimpleAuthorizationInfo(); // 模拟从数据库查询用户角色和权限 if (admin.equals(username)) { authorizationInfo.addRole(admin); authorizationInfo.addStringPermission(user:delete); authorizationInfo.addStringPermission(user:update); } else if (user.equals(username)) { authorizationInfo.addRole(user); authorizationInfo.addStringPermission(user:view); } return authorizationInfo; } /** * 认证逻辑验证用户身份 */ Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken (UsernamePasswordToken) token; String username upToken.getUsername(); String password new String(upToken.getPassword()); // 模拟数据库验证实际项目中应查询数据库 if (admin.equals(username) admin123.equals(password)) { return new SimpleAuthenticationInfo(username, password, getName()); } else if (user.equals(username) user123.equals(password)) { return new SimpleAuthenticationInfo(username, password, getName()); } throw new UnknownAccountException(用户名或密码错误); } }5. 控制器层与页面实现5.1 登录控制器创建登录相关的控制器处理用户认证请求package com.example.shirodemo.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; Controller public class LoginController { GetMapping(/login) public String loginPage() { // 如果已经登录直接跳转到首页 Subject subject SecurityUtils.getSubject(); if (subject.isAuthenticated()) { return redirect:/index; } return login; } PostMapping(/doLogin) public String doLogin(RequestParam String username, RequestParam String password, Model model) { try { Subject subject SecurityUtils.getSubject(); UsernamePasswordToken token new UsernamePasswordToken(username, password); subject.login(token); return redirect:/index; } catch (UnknownAccountException e) { model.addAttribute(error, 用户名不存在); } catch (IncorrectCredentialsException e) { model.addAttribute(error, 密码错误); } catch (LockedAccountException e) { model.addAttribute(error, 账户被锁定); } catch (AuthenticationException e) { model.addAttribute(error, 认证失败); } return login; } GetMapping(/logout) public String logout() { SecurityUtils.getSubject().logout(); return redirect:/login; } }5.2 业务控制器创建需要权限控制的业务接口package com.example.shirodemo.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; Controller public class BusinessController { GetMapping(/index) public String index(Model model) { model.addAttribute(message, 欢迎来到首页); return index; } GetMapping(/user/list) RequiresPermissions(user:view) public String userList(Model model) { model.addAttribute(users, 用户列表数据); return user/list; } GetMapping(/admin/dashboard) RequiresRoles(admin) public String adminDashboard(Model model) { model.addAttribute(adminInfo, 管理员仪表板数据); return admin/dashboard; } GetMapping(/403) public String unauthorized() { return error/403; } }5.3 前端页面模板创建简单的 Thymeleaf 模板页面登录页面 (login.html)!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title用户登录/title link relstylesheet th:href{/css/style.css} /head body div classlogin-container h2系统登录/h2 form th:action{/doLogin} methodpost div classform-group input typetext nameusername placeholder用户名 required /div div classform-group input typepassword namepassword placeholder密码 required /div button typesubmit登录/button /form div th:if${error} classerror-message th:text${error}/div /div /body /html首页 (index.html)!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title系统首页/title /head body h1 th:text${message}欢迎页面/h1 div a th:href{/user/list}查看用户列表/a | a th:href{/admin/dashboard}管理员面板/a | a th:href{/logout}退出登录/a /div /body /html6. 高级特性与最佳实践6.1 密码加密与安全在实际项目中明文存储密码是严重的安全隐患。Shiro 提供了强大的加密支持package com.example.shirodemo.config; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.crypto.hash.Sha256Hash; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class SecurityConfig { /** * 配置密码加密匹配器 */ Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher matcher new HashedCredentialsMatcher(); matcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME); matcher.setHashIterations(1024); // 哈希迭代次数 matcher.setStoredCredentialsHexEncoded(true); // 十六进制编码 return matcher; } /** * 密码加密工具方法 */ public static String encryptPassword(String password, String salt) { return new Sha256Hash(password, salt, 1024).toHex(); } } // 在自定义 Realm 中设置加密匹配器 Component public class CustomRealm extends AuthorizingRealm { Autowired public void setCredentialsMatcher(HashedCredentialsMatcher matcher) { super.setCredentialsMatcher(matcher); } Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { // 认证时自动进行密码匹配 String username (String) token.getPrincipal(); // 从数据库查询加密后的密码和盐值 String encryptedPassword 从数据库查询的加密密码; String salt 用户对应的盐值; return new SimpleAuthenticationInfo( username, encryptedPassword, ByteSource.Util.bytes(salt), getName() ); } }6.2 会话管理配置Shiro 提供了灵活的会话管理机制可以替代 HttpSessionConfiguration public class SessionConfig { /** * 配置会话管理器 */ Bean public SessionManager sessionManager() { DefaultWebSessionManager sessionManager new DefaultWebSessionManager(); // 设置会话超时时间毫秒 sessionManager.setGlobalSessionTimeout(1800000); // 30分钟 // 删除无效session sessionManager.setDeleteInvalidSessions(true); // 定时验证session sessionManager.setSessionValidationSchedulerEnabled(true); return sessionManager; } /** * 在安全管理器中注入会话管理器 */ Bean public DefaultWebSecurityManager securityManager(SessionManager sessionManager) { DefaultWebSecurityManager securityManager new DefaultWebSecurityManager(); securityManager.setRealm(customRealm()); securityManager.setSessionManager(sessionManager); return securityManager; } }6.3 注解式权限控制除了在配置文件中定义权限规则还可以使用注解进行细粒度控制RestController RequestMapping(/api) public class ApiController { GetMapping(/userInfo) RequiresAuthentication // 需要登录 public ResponseEntityUser getUserInfo() { // 获取当前用户信息 return ResponseEntity.ok(userService.getCurrentUser()); } PostMapping(/user) RequiresPermissions(user:create) // 需要创建权限 public ResponseEntity createUser(RequestBody User user) { userService.createUser(user); return ResponseEntity.ok().build(); } DeleteMapping(/user/{id}) RequiresPermissions(user:delete) // 需要删除权限 public ResponseEntity deleteUser(PathVariable Long id) { userService.deleteUser(id); return ResponseEntity.ok().build(); } GetMapping(/admin/report) RequiresRoles(admin) // 需要管理员角色 public ResponseEntityReport getAdminReport() { return ResponseEntity.ok(reportService.generateAdminReport()); } }7. 常见问题与解决方案7.1 启动类配置要点确保主启动类正确扫描到 Shiro 配置package com.example.shirodemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class ShiroDemoApplication { public static void main(String[] args) { SpringApplication.run(ShiroDemoApplication.class, args); } }7.2 权限注解不生效问题如果RequiresRoles等注解不生效需要在配置类中开启注解支持Configuration public class ShiroAnnotationConfig { /** * 开启Shiro注解支持 */ Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } /** * 支持AOP代理 */ Bean DependsOn(lifecycleBeanPostProcessor) public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } }7.3 静态资源被拦截问题如果CSS、JS等静态资源被Shiro拦截检查过滤器链配置// 在ShiroConfig的filterChainDefinitionMap中添加 filterChainDefinitionMap.put(/static/**, anon); filterChainDefinitionMap.put(/**.js, anon); filterChainDefinitionMap.put(/**.css, anon);7.4 会话持久化配置生产环境建议配置Redis等外部会话存储Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } Bean public SessionManager sessionManager() { DefaultWebSessionManager sessionManager new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; }8. 生产环境部署建议8.1 安全加固措施密码策略强制使用强密码定期更换会话安全设置合理的会话超时时间启用HTTPS权限最小化遵循最小权限原则避免过度授权日志审计记录重要操作日志便于追踪8.2 性能优化方案缓存配置对权限信息进行缓存减少数据库查询连接池优化配置合适的数据库连接池参数集群部署在集群环境下配置共享会话存储8.3 监控与告警健康检查实现Shiro组件的健康检查端点性能监控监控认证授权操作的响应时间安全告警对异常登录行为进行实时告警通过本文的完整实战指南你应该已经掌握了Spring Boot整合Apache Shiro的核心技术。在实际项目开发中建议根据业务需求灵活调整权限模型同时密切关注安全最佳实践。Shiro作为一个成熟稳定的安全框架能够为你的应用提供可靠的安全保障。
企业数字化 ERP 产品动态
相关推荐
AI代理技能扩展机制:Claude的Agent Skills解析与实践 1. Agent Skills 核心概念解析Agent Skills是Anthropic公司为Claude系列AI代理设计的一套能力扩展机制。简单来说,它就像给AI安装"技能插件"——通过结构化文件夹组织指令、脚本和资源,让通用AI代理快速获得特定领域的专业能力。这种设计源于一… · 2026/9/20 16:02:09
人形机器人五大平台深度对比:从Atlas到Optimus,开发者如何选型? 1. 人形机器人浪潮下的“全都要”哲学最近几年,人形机器人这个赛道真是越来越热闹了。从实验室里的概念验证,到科技展上的惊艳亮相,再到如今几款产品已经能摆在台面上让咱们普通消费者和开发者“品鉴”,这个进程比预想的要快得多。… · 2026/9/16 9:42:30
嵌入式C语言开发中的数据类型选择与避坑指南 1. 嵌入式开发中的数据类型基础认知在嵌入式C语言开发领域,u8、u16、u32这些数据类型缩写就像电工眼中的螺丝刀规格——看似简单却直接影响工程质量。我刚入行时曾在一个电机控制项目里,因为误用u16存储转速值导致数据溢出,结果电机突然"… · 2026/9/20 12:55:41
3个核心逻辑拆解美丽说 首页布局,避开高频面试题陷阱 3个核心逻辑拆解美丽说 首页布局,避开高频面试题陷阱 官方文档翻了三遍还是懵?别慌,这不是你的错,是资料太碎。 很多应届生准备 高频面试题 时,一看到“首页架构”这种题就发怵,觉得太虚。 其实把 美丽说 首页… · 2026/9/22 17:30:32
告别踩坑:一文搞懂两表关联查询的5个致命陷阱 告别踩坑:一文搞懂两表关联查询的5个致命陷阱 还在为数据库环境配置卡半天?别慌,这锅不全是你的。很多后端新人甚至资深开发,在写两表关联查询时,都掉进过同一个坑:看着代码没报错,结果数据却少了、多了,甚至内存直接爆了。今天这篇,我结合过去十年… · 2026/9/22 17:30:01
5分钟搞定图片分享完整示例,别再被环境配置坑 5分钟搞定图片分享完整示例,别再被环境配置坑 刚接手新项目,为了加个“图片分享”功能,配置环境就卡半天?Nginx 转发报错、CORS 跨域拦截、Base64 体积爆炸,这些问题是不是让你怀疑人生?别慌,今天这篇文章不讲虚的,直接上… · 2026/9/22 17:29:54
3天搞懂食补胶原蛋白项目,保姆级教程避坑指南 3天搞懂食补胶原蛋白项目,保姆级教程避坑指南 看了一堆教程还是不会写项目?别急,这不是你笨,是教程太碎。 今天这篇 保姆级教程 ,直接把【食补胶原蛋白】当成一个真实业务场景拆解。 我们不做空洞的理论,直接上手代码,把数据跑通。… · 2026/9/22 17:29:41
戴尔e6430驱动源码深扒与完整示例 戴尔e6430驱动源码深扒与完整示例 面试被问“戴尔 e6430 的 ACPI 事件是如何唤醒休眠的”,我卡壳了。这不仅是硬件冷知识,更是系统底层交互的试金石。为了补齐这块短板,我翻遍了 Linux 内核驱动源码,整理出这份 完整示例 。… · 2026/9/22 17:29:41
3个真实案例拆解abs-141坑点,面试必问的底层逻辑 3个真实案例拆解abs-141坑点,面试必问的底层逻辑 刚结束一场二面,候选人代码写得溜,但面试官问起 abs-141 在极端负数下的边界行为,他愣了五秒,支支吾吾答了个“返回绝对值”。面试官摇头,面试结束。这就是典型的… · 2026/9/22 17:29:22
5个电影海报图片处理坑,新手避坑指南 5个电影海报图片处理坑,新手避坑指南 刚写完代码,一运行屏幕直接炸了。满屏红色的 StackTrace 滚得比弹幕还快,什么 NullPointerException 、 ImageIO.read() returned null 、… · 2026/9/22 0:00:07
注册微信公众账号:一文搞懂从0到1全流程 注册微信公众账号:一文搞懂从0到1全流程 复制来的代码跑不通,报错信息满屏飞,到底卡在哪?别急,咱们先停下手里的调试。很多开发者觉得注册微信公众账号只是填个表单、传个身份证那么简单,真上手才发现坑深不见底。今天这篇 一文搞懂… · 2026/9/22 0:00:07