Spring Security 6+Opaque Token认证异常返回逻辑优化问询
Spring Security 6 + Opaque Token 异常处理方案
一、自定义认证服务器不可达异常
先定义专属异常类,用来标记「认证服务器连接失败/超时」的场景,方便后续精准区分处理:
public class IntrospectionServerUnavailableException extends AuthenticationException { public IntrospectionServerUnavailableException(String message, Throwable cause) { super(message, cause); } }
二、包装OpaqueTokenIntrospector捕获连接异常
自定义一个Introspector实现类,包装原有的Nimbus实现,在令牌校验过程中捕获RestTemplate抛出的连接超时、IO异常等,转换成上面的自定义异常:
@Component public class CustomOpaqueTokenIntrospector implements OpaqueTokenIntrospector { private final OpaqueTokenIntrospector delegate; public CustomOpaqueTokenIntrospector(@Value("${spring.security.oauth2.resourceserver.opaque-token.introspection-uri}") String introspectionUrl, @Value("${spring.security.oauth2.resourceserver.opaque-token.client-id}") String clientId, @Value("${spring.security.oauth2.resourceserver.opaque-token.client-secret}") String clientSecret, @Value("${introspection.connection-timeout:5}") int connectionTimeout, @Value("${introspection.read-timeout:5}") int readTimeout) { RestOperations restOperations = new RestTemplateBuilder() .basicAuthentication(clientId, clientSecret) .setConnectTimeout(Duration.ofSeconds(connectionTimeout)) .setReadTimeout(Duration.ofSeconds(readTimeout)) .build(); this.delegate = new NimbusOpaqueTokenIntrospector(introspectionUrl, restOperations); } @Override public OAuth2AuthenticatedPrincipal introspect(String token) { try { return delegate.introspect(token); } catch (OAuth2IntrospectionException e) { // 检查异常根源是否为连接/超时类异常 Throwable rootCause = e.getCause(); if (rootCause instanceof ConnectTimeoutException || rootCause instanceof SocketTimeoutException || rootCause instanceof IOException) { throw new IntrospectionServerUnavailableException("认证服务器连接失败", rootCause); } // 其他认证相关异常(如token无效、过期)继续抛出原异常 throw e; } } }
三、配置Spring Security异常处理
通过自定义认证/授权异常处理器,实现不同场景下的响应逻辑:
1. 自定义AuthenticationEntryPoint(处理认证异常)
区分「服务器不可达」和「普通认证失败」,分别返回500和带提示的401响应:
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.setContentType("application/json;charset=UTF-8"); if (authException instanceof IntrospectionServerUnavailableException) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.getWriter().write("{\"code\":500,\"message\":\"" + authException.getMessage() + "\"}"); } else { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("{\"code\":401,\"message\":\"" + authException.getMessage() + "\"}"); } } }
2. 自定义AccessDeniedHandler(处理授权异常)
返回带提示信息的403响应:
public class CustomAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { response.setContentType("application/json;charset=UTF-8"); response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().write("{\"code\":403,\"message\":\"权限不足,无法访问该资源\"}"); } }
3. 配置SecurityFilterChain
将自定义处理器接入Spring Security配置:
@Configuration @EnableWebSecurity public class SecurityConfig { private final CustomOpaqueTokenIntrospector customOpaqueTokenIntrospector; public SecurityConfig(CustomOpaqueTokenIntrospector customOpaqueTokenIntrospector) { this.customOpaqueTokenIntrospector = customOpaqueTokenIntrospector; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .opaqueToken(token -> token .introspector(customOpaqueTokenIntrospector) ) ) .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint(new CustomAuthenticationEntryPoint()) .accessDeniedHandler(new CustomAccessDeniedHandler()) ); return http.build(); } }
关键说明
- 异常区分逻辑:通过
OAuth2IntrospectionException的根源异常判断是否为连接类故障,这类场景属于服务不可用,返回500;其他如token无效、过期等认证失败场景,返回401。 - 响应格式:统一使用JSON返回提示信息,可根据业务需求调整JSON结构。
- 适配Spring Security 6:采用新版本的
oauth2ResourceServer().opaqueToken()配置API,符合框架规范。
内容的提问来源于stack exchange,提问作者Fabiano Armando
相关产品推荐
相关产品推荐

