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

Spring Reactive环境下OAuth2服务宕机时的自定义错误处理问询

解决方案:自定义OAuth2 JWKS获取异常的错误响应

当OAuth Server宕机导致Api Gateway无法获取JWKS时,默认的异常处理不会将这类错误转换为自定义响应格式。需要通过自定义JWT解码器和异常处理逻辑来实现需求,具体步骤如下:


1. 自定义JWT解码器,捕获JWKS获取异常

默认的jwkSetUri方法抛出的运行时异常不会被AuthenticationEntryPoint捕获,因此需要手动构建JwtDecoder,将JWKS相关异常转换为OAuth2认证异常:

@Bean
public JwtDecoder jwtDecoder(@Value("${app.jwk-set-uri:}") String jwksUri) {
    // 基于Nimbus构建JWT解码器
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwksUri).build();

    // 添加校验器,捕获JWKS获取异常并转换为OAuth2AuthenticationException
    jwtDecoder.setJwtValidator(jwt -> {
        try {
            return DefaultJwtValidator.instance.validate(jwt);
        } catch (RuntimeException e) {
            // 匹配JWKS获取失败的异常场景(网络错误、服务不可达等)
            if (e.getCause() instanceof ResourceAccessException || 
                e.getMessage().contains("Failed to retrieve JWKS")) {
                throw new OAuth2AuthenticationException(
                    new OAuth2Error("auth_server_unavailable", 
                    "认证服务暂时不可用,请稍后重试", null)
                );
            }
            throw e;
        }
    });

    return jwtDecoder;
}

2. 修改Security配置,使用自定义解码器

将原配置中jwkSetUri的调用替换为自定义的JwtDecoder:

@RefreshScope
@Bean
public SecurityWebFilterChain securityWebFilterChain(
        ServerHttpSecurity http,
        SecurityProperties securityProperties,
        JwtDecoder jwtDecoder) {

    log.info("Updated Public Endpoints: {}", securityProperties.getPublicEndpoints());

    var publicEndpoints = securityProperties.getPublicEndpoints();

    http
            .csrf(ServerHttpSecurity.CsrfSpec::disable)
            .authorizeExchange(exchange -> exchange.anyExchange().authenticated())
            .oauth2ResourceServer(oauth2 -> oauth2
                    .jwt(jwtSpec -> jwtSpec.decoder(jwtDecoder))
                    .authenticationEntryPoint(authenticationEntryPoint)
            )
            .exceptionHandling(exceptionHandling -> exceptionHandling
                    .authenticationEntryPoint(authenticationEntryPoint)
            );

    return http.build();
}

3. 完善AuthenticationEntryPoint,返回自定义响应

在自定义的ServerAuthenticationEntryPoint中处理OAuth2AuthenticationException,输出自定义错误模型:

@Component
public class CustomAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {

    @Override
    public Mono<Void> commence(ServerHttpRequest request, ServerHttpResponse response, AuthenticationException authException) {
        // 设置响应状态码(建议用503表示服务不可用)
        response.setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        // 构建自定义错误模型
        CustomErrorResponse errorResponse = new CustomErrorResponse();
        errorResponse.setCode("AUTH_SERVER_UNAVAILABLE");
        errorResponse.setMessage("认证服务暂时不可用,请稍后重试");
        errorResponse.setPath(request.getPath().value());

        // 转换为JSON并写入响应
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            byte[] jsonBytes = objectMapper.writeValueAsBytes(errorResponse);
            DataBuffer buffer = response.bufferFactory().wrap(jsonBytes);
            return response.writeWith(Mono.just(buffer));
        } catch (JsonProcessingException e) {
            return response.setComplete();
        }
    }
}

// 自定义错误模型类
public class CustomErrorResponse {
    private String code;
    private String message;
    private String path;

    // Getter和Setter方法
    public String getCode() { return code; }
    public void setCode(String code) { this.code = code; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public String getPath() { return path; }
    public void setPath(String path) { this.path = path; }
}

关键说明

  • JWKS获取失败的异常属于运行时异常,必须手动转换为OAuth2AuthenticationException才能被AuthenticationEntryPoint捕获
  • 响应状态码建议使用503 SERVICE_UNAVAILABLE,更准确反映服务不可用的场景
  • 可根据实际需求扩展异常匹配规则,覆盖更多JWKS获取失败的场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:52:43