如何为带JwkSetUri的JWT解码器配置代理并适配ReactiveJwtDecoder
问题分析与解决方案
你遇到的核心问题是类型不匹配:当前的Security配置基于Servlet栈(继承WebSecurityConfigurerAdapter),oauth2ResourceServer().jwt().decoder()要求传入JwtDecoder类型的Bean,但你配置的是Reactive栈的ReactiveJwtDecoder,导致代码报错。
以下是两种适配代理环境的解决方案,优先推荐第一种(无需修改架构):
方案1:保持Servlet栈,给NimbusJwtDecoder配置代理
直接为原有的JwtDecoder添加代理支持,无需切换到Reactive架构:
步骤1:配置带代理的HTTP请求工厂
@Bean public ClientHttpRequestFactory clientHttpRequestFactory() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); // 配置代理地址和端口 Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("http.proxy.example.com", 8000)); factory.setProxy(proxy); return factory; } @Bean public RestTemplate restTemplate(ClientHttpRequestFactory factory) { return new RestTemplate(factory); }
步骤2:修改JwtDecoder配置,引入代理的RestTemplate
同时修正你之前的issuer配置错误(原代码把JWK地址当成了issuer,这会导致令牌验证失败):
@Bean public JwtDecoder jwtDecoder(RestTemplate restTemplate) { // 正确的Azure AD租户Issuer地址 String issuerUri = "https://login.microsoftonline.com/7521acbc-a68c-41e5-a975-1cf83066dd19/v2.0"; String jwkSetUri = "https://login.microsoftonline.com/7521acbc-a68c-41e5-a975-1cf83066dd19/discovery/v2.0/keys"; NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri) .restOperations(restTemplate) // 注入带代理的RestTemplate .build(); // 配置令牌验证规则 OAuth2TokenValidator<Jwt> defaultValidator = JwtValidators.createDefaultWithIssuer(issuerUri); jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>( defaultValidator, new CustomTokenValidator() )); return jwtDecoder; }
步骤3:保留原有的configure(HttpSecurity)方法
此时jwtDecoder()返回的是符合要求的JwtDecoder类型,原代码无需修改:
protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/**").authenticated() .anyRequest().permitAll() .and() .oauth2ResourceServer().jwt().decoder(jwtDecoder()); }
方案2:切换到Reactive栈(需项目支持WebFlux)
如果你的项目可以切换为Spring WebFlux架构,可使用Reactive版本的配置:
步骤1:引入WebFlux依赖
在pom.xml中添加:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
步骤2:修改Security配置为Reactive风格
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchanges -> exchanges .pathMatchers("/api/**").authenticated() .anyExchange().permitAll() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.decoder(jwtDecoder())) ) .build(); } @Bean public HttpClient httpClient() { return HttpClient.create() .proxy(proxySpec -> proxySpec .type(ProxyProvider.Proxy.HTTP) .host("http.proxy.example.com") .port(8000) ); } @Bean public ReactiveJwtDecoder jwtDecoder() { String issuerUri = "https://login.microsoftonline.com/7521acbc-a68c-41e5-a975-1cf83066dd19/v2.0"; String jwkSetUri = "https://login.microsoftonline.com/7521acbc-a68c-41e5-a975-1cf83066dd19/discovery/v2.0/keys"; WebClient webClient = WebClient.builder() .clientConnector(new ReactorClientHttpConnector(httpClient())) .build(); NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri) .webClient(webClient) .build(); OAuth2TokenValidator<Jwt> defaultValidator = JwtValidators.createDefaultWithIssuer(issuerUri); decoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>( defaultValidator, new CustomTokenValidator() )); return decoder; } private static class CustomTokenValidator implements OAuth2TokenValidator<Jwt> { @Override public OAuth2TokenValidatorResult validate(Jwt jwt) { if (jwt.getSubject() == null || jwt.getSubject().isEmpty()) { return OAuth2TokenValidatorResult.failure(); } else { return OAuth2TokenValidatorResult.success(); } } } }
内容的提问来源于stack exchange,提问作者BHL
相关产品推荐
相关产品推荐

