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

Spring Authorization Server实现自定义authenticationProvider遇403问题咨询

问题根因

你当前返回403的核心原因有三个:

  • 未配置Spring Security 5资源服务器的核心处理逻辑,默认过滤器链不会走你自定义的AuthenticationProvider
  • 缺少替代原有tokenExtractor的转换器,没有生成对应类型的待认证对象,请求无法进入认证流程
  • 使用了授权服务器侧的OAuth2AccessTokenAuthenticationToken作为返回值,资源服务器侧不识别该认证类型

解决方案

完整适配后的本地环境配置如下,完全兼容原有业务代码中获取认证信息、读取claim的逻辑,无需调整业务层代码:

@Configuration
@EnableWebSecurity
@Profile("local")
public class ResourceServerConfigurationLocal extends WebSecurityConfigurerAdapter {

    private static final String LOCAL = "local";
    @Value("${id.local.oauth}")
    private String id;
    @Value("${clientId.local.oauth}")
    private Integer clientId;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .requestMatchers()
                .antMatchers("/api/**")
                .and()
            .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
            // 配置OAuth2资源服务器,绑定自定义转换器和认证逻辑
            .oauth2ResourceServer(oauth2 -> oauth2
                .bearerTokenConverter(customBearerTokenConverter())
                .authenticationManager(authenticationManager())
            )
            .authenticationProvider(localAuthenticationProvider());
    }

    // 替代原有tokenExtractor:无论请求是否带token,都生成待认证的令牌对象
    private Converter<HttpServletRequest, BearerTokenAuthenticationToken> customBearerTokenConverter() {
        return request -> new BearerTokenAuthenticationToken(LOCAL);
    }

    @Bean
    public AuthenticationProvider localAuthenticationProvider() {
        return new AuthenticationProvider() {
            @Override
            public Authentication authenticate(Authentication authentication) {
                log.info("Logged with ID: {}", id);
                CustomUserDetails userDetails = CustomUserDetails.builder().userId(clientId).build();
                // 可根据测试需要自定义权限列表
                List<GrantedAuthority> authorities = Collections.emptyList();
                // 填充需要的claim,完全兼容原有代码的取值逻辑
                Map<String, Object> claims = new HashMap<>();
                claims.put("sub", id);
                claims.put("client_id", clientId.toString());
                claims.put("user_details", userDetails);

                // 返回资源服务器可识别的认证对象
                return new BearerTokenAuthentication(
                    new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, LOCAL, 
                        Instant.now(), Instant.now().plus(Duration.ofDays(1))),
                    authorities,
                    claims
                );
            }

            @Override
            public boolean supports(Class<?> authentication) {
                return BearerTokenAuthenticationToken.class.isAssignableFrom(authentication);
            }
        };
    }
}

注意事项

如果需要调整返回的认证信息结构,直接修改claims的填充逻辑即可,原有业务代码中从SecurityContext获取认证信息、读取claim的逻辑不需要做任何改动,该配置仅在local环境生效,和生产环境的JWT认证逻辑完全隔离。

内容的提问来源于stack exchange,提问作者Juan Pablo Meza Utreras

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 00:18:03