Spring Boot整合Shiro案例

wen java案例 3

Spring Boot整合Shiro案例实战:从零搭建权限管理框架(附完整代码)


目录导读(Table of Contents)

  1. 为什么要在Spring Boot中使用Shiro?
  2. 环境准备与核心依赖配置
  3. Shiro核心组件详解(Subject/SecurityManager/Realm)
  4. 案例实战:用户登录认证与角色授权
    • 1 自定义Realm实现
    • 2 配置ShiroConfig核心类
    • 3 登录与退出逻辑封装
    • 4 注解式权限控制(@RequiresPermissions)
  5. 常见问题与解决方案(FAQ)
  6. 性能优化与安全建议

为什么要在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(基于角色的访问控制)系统,覆盖认证、授权、会话管理等企业级需求。

Spring Boot整合Shiro案例


环境准备与核心依赖配置

  • 开发环境: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会自动配置DefaultWebSecurityManagerShiroFilterFactoryBean,大幅减少XML配置,同时需要引入shiro-core(用于缓存)、shiro-ehcache(可选二级缓存),如果使用JWT,还需额外引入jwt依赖。


Shiro核心组件详解(Subject/SecurityManager/Realm)

  • Subject:当前用户操作抽象,封装认证状态、会话属性,通过SecurityUtils.getSubject()获取。
  • SecurityManager:核心调度器,管理所有Subject的认证与授权操作。
  • Realm:数据访问层,负责从数据库查询用户信息并封装为AuthenticationInfoAuthorizationInfo
    三者关系: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攻击。
  • 密码策略:使用PBKDF2BCrypt替代MD5(若业务允许),提高抗暴力破解能力。
  • 动态权限:将权限规则存入数据库,通过自定义Filter动态加载,避免硬编码URL规则。

本案例完整展示了Spring Boot整合Shiro的认证授权流程,从Realm到过滤器链的配置均给出可运行代码,实际项目中可根据需要扩展多Realm认证或JWT无状态登录,尝试修改后,你会感受到Shiro在轻量级权限管理中的独特魅力。

抱歉,评论功能暂时关闭!