Spring Boot整合Shiro案例实战:从零搭建权限管理框架(附完整代码)
目录导读(Table of Contents)
- 为什么要在Spring Boot中使用Shiro?
- 环境准备与核心依赖配置
- Shiro核心组件详解(Subject/SecurityManager/Realm)
- 案例实战:用户登录认证与角色授权
- 1 自定义Realm实现
- 2 配置ShiroConfig核心类
- 3 登录与退出逻辑封装
- 4 注解式权限控制(@RequiresPermissions)
- 常见问题与解决方案(FAQ)
- 性能优化与安全建议
为什么要在Spring Boot中使用Shiro?
在传统SSM项目中,Apache Shiro凭借轻量级、易扩展的特性成为Java安全框架的首选,随着Spring Boot的普及,自动配置特性让Shiro集成更加高效,与Spring Security相比,Shiro的API更直观,且支持会话管理、加密模块和多Realm认证,本案例将演示如何用Spring Boot 2.7.x + Shiro 1.9.x构建一个完整的RBAC(基于角色的访问控制)系统,覆盖认证、授权、会话管理等企业级需求。

环境准备与核心依赖配置
- 开发环境:JDK 1.8+、Maven 3.6+、MySQL 8.0、Spring Boot 2.7.14
- 核心依赖(pom.xml关键片段):
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.9.0</version> </dependency>
该Starter会自动配置
DefaultWebSecurityManager和ShiroFilterFactoryBean,大幅减少XML配置,同时需要引入shiro-core(用于缓存)、shiro-ehcache(可选二级缓存),如果使用JWT,还需额外引入jwt依赖。
Shiro核心组件详解(Subject/SecurityManager/Realm)
- Subject:当前用户操作抽象,封装认证状态、会话属性,通过
SecurityUtils.getSubject()获取。 - SecurityManager:核心调度器,管理所有Subject的认证与授权操作。
- Realm:数据访问层,负责从数据库查询用户信息并封装为
AuthenticationInfo和AuthorizationInfo。
三者关系:Subject(当前用户)→SecurityManager(安全管理器)→Realm(数据源),理解这条链路是整合的关键。
案例实战:用户登录认证与角色授权
1 自定义Realm实现
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
// 认证逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
String username = (String) token.getPrincipal();
User user = userService.findByUsername(username);
if (user == null) {
throw new UnknownAccountException("账号不存在");
}
// 使用盐值加密(需自定义CredentialsMatcher)
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), salt, getName());
}
// 授权逻辑(查询用户角色和权限)
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
Set<String> roles = userService.findRolesByUsername(username);
Set<String> permissions = userService.findPermsByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.setStringPermissions(permissions);
return info;
}
}
关键点:数据库密码必须使用MD5+盐加密,同时配置HashedCredentialsMatcher匹配器,确保安全。
2 配置ShiroConfig核心类
@Configuration
public class ShiroConfig {
@Bean
public Realm userRealm() { return new UserRealm(); }
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(userRealm());
return manager;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
// 匿名访问登录接口
definition.addPathDefinition("/login", "anon");
// 需要认证的接口
definition.addPathDefinition("/**", "authc");
return definition;
}
}
Spring Boot集成时需注意:ShiroFilterChainDefinition负责URL过滤规则,而ShiroFilterFactoryBean负责生成Filter链。
3 登录与退出逻辑封装
@RestController
public class LoginController {
@PostMapping("/login")
public Result login(@RequestBody UserDTO dto) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(dto.getUsername(), dto.getPassword());
try {
subject.login(token); // 触发Realm认证
return Result.success("登录成功");
} catch (AuthenticationException e) {
return Result.error(e.getMessage());
}
}
@GetMapping("/logout")
public Result logout() {
SecurityUtils.getSubject().logout();
return Result.success("退出成功");
}
}
4 注解式权限控制(@RequiresPermissions)
在Controller方法添加注解即可实现方法级权限校验:
@GetMapping("/user/delete")
@RequiresPermissions("user:delete") // 无权限时抛UnauthorizedException
public Result deleteUser() { ... }
需在ShiroConfig启用注解支持:
@Bean
public AuthorizationAttributeSourceAdvisor advisor() {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager());
return advisor;
}
常见问题与解决方案(FAQ)
Q1:登录后无法访问受保护资源?
→ 检查ShiroFilterChainDefinition中URL规则顺序,authc必须放在最后;同时确认securityManager中正确注入Realm。
Q2:@RequiresPermissions注解不生效?
→ 代理失效导致,需在启动类添加@EnableAspectJAutoProxy(exposeProxy = true),并重新加载Advisor配置。
Q3:密码加盐后无法匹配?
→ 确保自定义HashedCredentialsMatcher设置了hashAlgorithmName="MD5"且hashIterations=2(与加密次数一致)。
Q4:如何全局捕获Shiro异常?
→ 使用@RestControllerAdvice统一捕获AuthorizationException,返回403状态码和JSON响应,而非默认跳转页面。
性能优化与安全建议
- 缓存优化:启用Ehcache缓存角色/权限数据,减少数据库查询(
securityManager.setCacheManager(ehCacheManager()))。 - 会话安全:设置会话超时时间(默认30分钟),并配置Cookie的
HttpOnly属性防止XSS攻击。 - 密码策略:使用
PBKDF2或BCrypt替代MD5(若业务允许),提高抗暴力破解能力。 - 动态权限:将权限规则存入数据库,通过自定义
Filter动态加载,避免硬编码URL规则。
本案例完整展示了Spring Boot整合Shiro的认证授权流程,从Realm到过滤器链的配置均给出可运行代码,实际项目中可根据需要扩展多Realm认证或JWT无状态登录,尝试修改后,你会感受到Shiro在轻量级权限管理中的独特魅力。