在复杂的业务系统中,安全控制(认证、授权、加密)是核心需求。相比于 Spring Security 的重量级设计,Apache Shiro 凭借其简洁的 API 和灵活的扩展性,成为许多开发者的优选方案。本文将手把手演示如何在 Spring Boot 3 中整合 Shiro 1.12.0+,实现完整的权限管理功能。
在 pom.xml
中添加关键依赖:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-spring-boot-starterartifactId>
<version>1.12.0version>
<classifier>jakartaclassifier>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
dependencies>
创建 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;
}
}
创建 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()
);
}
}
在 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) {
// 业务逻辑
}
}
通过 @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, "认证失败"));
}
}
@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;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("SHA-256");
matcher.setHashIterations(1024);
matcher.setStoredCredentialsHexEncoded(false);
return matcher;
}
// 在 Realm 中设置
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
@EnableAspectJAutoProxy
public
且通过代理对象调用CachingRealm
减少数据库查询sessionManager
的全局会话上限通过本文,您已完成 Spring Boot 3 与 Apache Shiro 的深度整合。相比 Spring Security,Shiro 的配置更简洁,适合中小型项目快速实现安全控制。建议根据实际业务需求调整认证策略和缓存机制。
扩展阅读:Shiro官方文档
希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!