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

Spring Boot JWT授权异常:有效令牌仍返回401 Unauthorized

问题排查:Spring Boot JWT授权有效令牌仍返回401 Unauthorized

核心问题

在Spring Boot项目中配置JWT授权后,即使使用有效令牌,所有接口(含Swagger UI)均返回401 Unauthorized异常。相关配置代码如下:

Web安全配置类

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "authority")
@Profile({"cloud", "development", "release"})
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private Map<String, String> data = new LinkedHashMap<>();
    private List<String> whiteList = new ArrayList<>();

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       
        http.authorizeRequests().antMatchers("/api/v1/students").authenticated()
                .and().authorizeRequests().antMatchers("/api/v1/students/*").authenticated()
                .and().authorizeRequests().antMatchers("/api/v1/students/*").access("hasRole('learning_management_admin_app1000000')")
                      .and().authorizeRequests().antMatchers("/api/v1/students").access("hasRole('learning_management_admin_app1000000')");


        http.csrf().disable().authorizeRequests().antMatchers(getWhiteList().toArray(new String[0]))
                .permitAll();

        http.cors();
        Okta.configureResourceServer401ResponseBody(http);
    }

    public List<String> getWhiteList() {
       // 省略实现
    }
}

控制器代码

@Validated
@CrossOrigin("*")
@RestController
@RequestMapping("/api/v1")
@SecurityRequirement(name = "BearerAuth")
@PreAuthorize("isAuthenticated()")
public class StudentsController {

 @GetMapping("change-requests")
    @PreAuthorize("hasAuthority('learning_management_admin_app1000000')")
 public ResponseEntity<List<Student>> getStudents(
            @RequestParam(required = false) String name) {
        // 省略实现
    }
}

排查方向及解决方案

1. 安全规则顺序错误

Spring Security的规则是从上到下匹配,一旦匹配就停止后续规则。你当前先配置了/api/v1/students等路径的认证/授权规则,之后才设置白名单的permitAll,这会导致白名单规则永远无法触发,所有请求都会被前面的规则拦截。

修复方法:调整规则顺序,先配置白名单,再配置需要认证的路径:

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 先放行白名单路径
    http.csrf().disable()
        .authorizeRequests()
        .antMatchers(getWhiteList().toArray(new String[0])).permitAll()
        // 再配置需要认证和授权的路径
        .antMatchers("/api/v1/students", "/api/v1/students/*")
            .authenticated()
            .access("hasAuthority('learning_management_admin_app1000000')")
        // 其他所有请求默认需要认证
        .anyRequest().authenticated();

    http.cors();
    Okta.configureResourceServer401ResponseBody(http);
}

2. 白名单未包含Swagger路径

如果Swagger UI的访问路径不在白名单中,会被拦截返回401。需要确认whiteList是否包含以下Swagger常用路径:

  • /swagger-ui/**
  • /swagger-resources/**
  • /v3/api-docs/**
  • /webjars/**

修复方法:在getWhiteList方法中补充这些路径:

public List<String> getWhiteList() {
    if (whiteList.isEmpty()) {
        whiteList.add("/swagger-ui/**");
        whiteList.add("/swagger-resources/**");
        whiteList.add("/v3/api-docs/**");
        whiteList.add("/webjars/**");
        // 其他业务白名单路径
    }
    return whiteList;
}

3. hasRole与hasAuthority前缀不匹配

Spring Security中hasRole默认会自动添加ROLE_前缀,而hasAuthority直接使用传入的字符串。如果你的JWT令牌中的角色没有ROLE_前缀,使用hasRole('learning_management_admin_app1000000')会实际检查ROLE_learning_management_admin_app1000000,与控制器中hasAuthority的校验逻辑不一致,导致授权失败。

修复方法:统一校验规则:

  • 将配置中的access("hasRole('xxx')")改为access("hasAuthority('learning_management_admin_app1000000')")
  • 或者如果令牌中角色确实带ROLE_前缀,将控制器中的hasAuthority改为hasRole

4. JWT资源服务器配置不完整

仅调用Okta.configureResourceServer401ResponseBody(http)不足以完成JWT的验证配置,需要确保已配置JWT的issuer、audience等核心参数。

修复方法:在配置文件中添加Okta相关配置:

okta.oauth2.issuer=https://你的Okta域名/oauth2/default
okta.oauth2.audience=api://default

或者手动配置JWT解码器:

@Bean
public JwtDecoder jwtDecoder() {
    return JwtDecoders.fromIssuerLocation("https://你的Okta域名/oauth2/default");
}

5. 全局方法安全注解生效问题

虽然添加了@EnableGlobalMethodSecurity(prePostEnabled = true),但需确保Spring能扫描到控制器中的@PreAuthorize注解。另外,控制器类上的@PreAuthorize("isAuthenticated()")会强制所有接口需要认证,若令牌解析失败也会返回401。

验证方法:临时移除控制器类上的@PreAuthorize注解,测试单个接口是否能正常访问,排查是否为方法级注解的问题。


内容的提问来源于stack exchange,提问作者MA-Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:35:29