You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security基于用户角色的请求授权失效问题排查

问题分析与解决方案

核心问题定位

从调试日志里的JWT内容能直接揪出关键问题:"roles":[]——生成的JWT里完全没包含用户的角色信息,导致授权过滤器解析后拿到的角色集合是空的,自然无法通过权限校验,返回403。

另外还有两个次要问题影响功能:

  • 安全规则的匹配顺序逻辑错误
  • 部分请求路径配置缺失开头的斜杠

具体修复步骤

1. 修复JWT生成逻辑(最关键)

检查你的CustomAuthenticationFilter(登录过滤器),确保登录成功生成JWT时,正确将用户角色写入roles声明。示例代码参考:

// 登录成功后生成JWT的核心代码片段
UserDetails userDetails = ...; // 获取当前登录用户的UserDetails实例
String[] roles = userDetails.getAuthorities().stream()
    .map(GrantedAuthority::getAuthority)
    .toArray(String[]::new);

// 生成JWT时必须正确写入roles字段
String token = JWT.create()
    .withSubject(userDetails.getUsername())
    .withArrayClaim("roles", roles)
    .withExpiresAt(new Date(System.currentTimeMillis() + 86400000)) // 示例过期时间
    .sign(Algorithm.HMAC256(secretKey.getBytes()));

2. 调整安全规则匹配顺序

Spring Security的规则是从上到下匹配,一旦匹配就停止后续规则判断。你当前的配置里,ROLE_USER的GET规则会先匹配/api/v1/movies/**,导致ROLE_ADMIN的同路径规则永远不会生效。需要把权限要求更高的规则放在前面:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    AbstractAuthenticationProcessingFilter filter = new CustomAuthenticationFilter(authenticationManager());
    filter.setFilterProcessesUrl("/api/v1/login");

    http.csrf().disable();
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    
    // 开放接口配置
    http.authorizeHttpRequests()
        .requestMatchers("/api/v1/login/**", "/api/token/refresh/**").permitAll()
        .requestMatchers(GET, "/api/v1/user/**").permitAll()
        // 先配置ADMIN的规则,再配置USER的规则
        .requestMatchers(GET, "/api/v1/movies/**", "/api/v1/reviews", "/api/v1/user").hasAnyAuthority("ROLE_ADMIN")
        .requestMatchers(GET, "/api/v1/movies/**", "/api/v1/reviews").hasAnyAuthority("ROLE_USER")
        // 修复路径开头缺失的斜杠
        .requestMatchers(POST, "/api/v1/movies/**", "/api/v1/reviews/**", "/api/v1/user/**").hasAuthority("ROLE_ADMIN")
        .requestMatchers(PUT, "/api/v1/movies/**", "/api/v1/reviews/**", "/api/v1/user/**").hasAuthority("ROLE_ADMIN")
        .requestMatchers(DELETE, "/api/v1/movies/**", "/api/v1/reviews/**", "/api/v1/user/**").hasAuthority("ROLE_SUPER_ADMIN")
        .anyRequest().authenticated();
    
    http.addFilter(filter);
    http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);

    return http.build();
}

3. 修复路径配置错误

你当前的POST/PUT/DELETE规则里,部分路径少了开头的/(比如api/v1/movies/**),这会导致规则匹配失效,所有路径都要统一写成/api/v1/movies/**这种完整格式。


验证建议

  1. 登录后解码JWT,确认roles字段包含正确的角色值(比如["ROLE_USER"]或["ROLE_ADMIN"])
  2. 用不同角色的用户测试对应端点,观察授权是否正常
  3. 可以在CustomAuthorizationFilter里添加日志,打印解析后的authorityCollections,确认角色是否正确加载

内容的提问来源于stack exchange,提问作者ABAB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:08:09