[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官方文檔
希望本教程對您有幫助,請點贊??收藏?關注支持!歡迎在評論區留言交流技術細節!