[Java实战]Spring Boot 3 整合 Apache Shiro(二十一)
引言
在复杂的业务系统中,安全控制(认证、授权、加密)是核心需求。相比于 Spring Security 的重量级设计,Apache Shiro 凭借其简洁的 API 和灵活的扩展性,成为许多开发者的优选方案。本文将手把手演示如何在 Spring Boot 3 中整合 Shiro 1.12.0+,实现完整的权限管理功能。
一、环境准备
- openJDK 17+(Spring Boot 3 强制要求)
- Spring Boot 3.4.5
- Apache Shiro 1.12.0(支持 Jakarta EE 9+)
- Maven/Gradle(本文使用 Maven)
- Redis(可选,用于会话管理)
二、项目依赖配置
在 pom.xml
中添加关键依赖:
<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Shiro Core --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.12.0</version><classifier>jakarta</classifier></dependency><!-- Servlet API (兼容性) --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency>
</dependencies>
三、核心组件配置
1. Shiro 配置类
创建 ShiroConfig.java
定义安全规则:
@Configuration
public class ShiroConfig {// 注入自定义 Realm@Beanpublic UserRealm userRealm() {return new UserRealm();}// 配置 SecurityManager@Beanpublic SecurityManager securityManager(UserRealm userRealm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(userRealm);securityManager.setRememberMeManager(rememberMeManager());return securityManager;}// 配置 Shiro 过滤器@Beanpublic ShiroFilterChainDefinition shiroFilterChainDefinition() {DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();chain.addPathDefinition("/login", "anon"); // 匿名访问chain.addPathDefinition("/logout", "logout"); // 退出登录chain.addPathDefinition("/**", "authc"); // 需要认证return chain;}// 记住我功能@Beanpublic RememberMeManager rememberMeManager() {CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();rememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));return rememberMeManager;}
}
2. 自定义 Realm 实现
创建 UserRealm.java
实现认证与授权逻辑:
public class UserRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;// 授权逻辑@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();String username = (String) principals.getPrimaryPrincipal();// 查询用户角色和权限User user = userService.findByUsername(username);info.setRoles(user.getRoles());info.setStringPermissions(user.getPermissions());return info;}// 认证逻辑@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {UsernamePasswordToken upToken = (UsernamePasswordToken) token;String username = upToken.getUsername();User user = userService.findByUsername(username);if (user == null) {throw new UnknownAccountException("用户不存在");}return new SimpleAuthenticationInfo(username, user.getPassword(), ByteSource.Util.bytes(user.getSalt()),getName());}
}
四、权限控制实战
1. 控制器层注解控制
在 Controller 方法上使用 Shiro 注解:
@RestController
@RequestMapping("/user")
public class UserController {@RequiresRoles("admin") // 需要admin角色@GetMapping("/list")public ResponseEntity<List<User>> listUsers() {// 业务逻辑}@RequiresPermissions("user:delete") // 需要删除权限@DeleteMapping("/{id}")public ResponseEntity<Void> deleteUser(@PathVariable Long id) {// 业务逻辑}
}
2. 统一异常处理
通过 @ControllerAdvice
捕获 Shiro 异常:
@Slf4j
@ControllerAdvice
public class ShiroExceptionHandler {@ExceptionHandler(AuthorizationException.class)public ResponseEntity<ApiResponse<?>> handleAuthError(AuthorizationException e) {return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ApiResponse<>(403, "权限不足"));}@ExceptionHandler(AuthenticationException.class)public ResponseEntity<ApiResponse<?>> handleLoginError(AuthenticationException e) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new ApiResponse<>(401, "认证失败"));}
}
五、高级功能扩展
1. 集成 Redis 会话管理
@Bean
public SessionDAO sessionDAO() {RedisSessionDAO sessionDAO = new RedisSessionDAO();sessionDAO.setRedisManager(redisManager());return sessionDAO;
}@Bean
public RedisManager redisManager() {RedisManager manager = new RedisManager();manager.setHost("localhost:6379");manager.setDatabase(0);return manager;
}
2. 密码加密配置
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();matcher.setHashAlgorithmName("SHA-256");matcher.setHashIterations(1024);matcher.setStoredCredentialsHexEncoded(false);return matcher;
}// 在 Realm 中设置
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
六、常见问题排查
1. 权限注解不生效
- 检查是否开启 AOP 支持:在配置类添加
@EnableAspectJAutoProxy
- 确认方法为
public
且通过代理对象调用
2. 会话失效异常
- 检查 Redis 连接配置
- 确保 SessionDAO 实现已正确注入
七、性能优化建议
- 缓存授权信息:使用
CachingRealm
减少数据库查询 - 限制会话数量:配置
sessionManager
的全局会话上限 - 启用集群模式:通过 Redis 实现分布式会话
结语
通过本文,您已完成 Spring Boot 3 与 Apache Shiro 的深度整合。相比 Spring Security,Shiro 的配置更简洁,适合中小型项目快速实现安全控制。建议根据实际业务需求调整认证策略和缓存机制。
扩展阅读:Shiro官方文档
希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!