[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
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
// 配置 SecurityManager
@Bean
public SecurityManager securityManager(UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
// 配置 Shiro 过滤器
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
chain.addPathDefinition("/login", "anon"); // 匿名访问
chain.addPathDefinition("/logout", "logout"); // 退出登录
chain.addPathDefinition("/**", "authc"); // 需要认证
return chain;
}
// 记住我功能
@Bean
public RememberMeManager rememberMeManager() {
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
rememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
return rememberMeManager;
}
}
2. 自定义 Realm 实现
创建 UserRealm.java
实现认证与授权逻辑:
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
// 授权逻辑
@Override
protected 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;
}
// 认证逻辑
@Override
protected 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官方文档
希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!