升级Spring Boot 3与Spring Security 6后遭遇Access Denied异常
问题分析与修复方案
核心问题
- OAuth2资源服务器未启用:你的SecurityFilterChain配置中缺少OAuth2资源服务器的核心配置逻辑,导致Spring Security无法解析请求头中的Bearer令牌,所有请求都被识别为匿名用户。
- 方法级安全覆盖白名单配置:控制器类上标注的
@PreAuthorize("isAuthenticated()")会覆盖HttpSecurity中设置的permitAll()规则,即使是白名单URL也会触发认证检查。
具体修复步骤
1. 完善SecurityFilterChain配置,启用JWT解析
修改filterChain方法,添加OAuth2资源服务器的JWT支持,让Spring Security能够正确处理Bearer令牌:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ http.csrf().disable() .authorizeHttpRequests((requests) -> requests .requestMatchers("/api/v1/students", "/api/v1/students/*").authenticated() // Spring Security 6中hasAnyRole会自动添加ROLE_前缀,若Okta返回的权限是admin,建议改用hasAuthority .requestMatchers(HttpMethod.PUT, "/api/v1/students/*").hasAuthority("admin") .requestMatchers(this.getWhiteList().toArray(new String[0])).permitAll() .anyRequest().authenticated() ) // 启用OAuth2资源服务器JWT解析 .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) .cors(); Okta.configureResourceServer401ResponseBody(http); return http.build(); }
2. 解决白名单与方法级安全的冲突
由于控制器类上的@PreAuthorize("isAuthenticated()")会强制所有方法进行认证检查,需做以下调整之一:
- 移除类级注解:将认证规则统一放在HttpSecurity中配置,删除
StudentController类上的@PreAuthorize("isAuthenticated()"); - 方法级覆盖:给白名单对应的控制器方法添加
@PreAuthorize("permitAll()"),覆盖类级规则:
@GetMapping("/students/count") @PreAuthorize("permitAll()") public ResponseEntity<Long> getStudentCount() { // 业务逻辑实现 }
3. 精简依赖配置
Okta Spring Boot Starter已经间接依赖了Spring Security的核心包,无需显式引入spring-security-web和spring-security-config,避免版本冲突:
ext { springBootVersion = '3.1.0' springCloudVersion = '2022.0.0-M3' } implementation 'com.okta.spring:okta-spring-boot-starter:3.0.3'
4. 验证Okta配置
确保配置文件中正确填写Okta的issuer和audience参数:
okta.oauth2.issuer=https://你的Okta域名/oauth2/default okta.oauth2.audience=api://default
内容的提问来源于stack exchange,提问作者MA-Dev
相关产品推荐
相关产品推荐

