如何自定义Spring Authorization Server令牌端点的异常处理
针对授权码交换令牌时需要添加额外校验、自定义错误信息/错误码及非标准HTTP状态码的需求,可通过以下两种方案实现:
方案1:扩展AuthenticationProvider拦截校验逻辑(推荐)
授权码交换的核心校验逻辑由OAuth2AuthorizationCodeAuthenticationProvider处理,我们可以扩展这个类插入自定义校验,并通过全局Filter捕获自定义异常来控制响应。
步骤1:自定义AuthenticationProvider
扩展默认的授权码校验提供者,在父类校验通过后添加自定义逻辑,校验失败时抛出携带自定义信息的异常:
@Component public class CustomAuthorizationCodeAuthenticationProvider extends OAuth2AuthorizationCodeAuthenticationProvider { public CustomAuthorizationCodeAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) { super(authorizationService, tokenGenerator); } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // 执行默认授权码校验 OAuth2AuthorizationCodeAuthenticationToken authToken = (OAuth2AuthorizationCodeAuthenticationToken) super.authenticate(authentication); // 自定义额外校验逻辑(示例:检查用户状态) OAuth2User user = (OAuth2User) authToken.getPrincipal(); if (!"ACTIVE".equals(user.getAttribute("status"))) { throw new CustomOAuth2AuthException("USER_INACTIVE", "用户已禁用", HttpStatus.FORBIDDEN.value()); } return authToken; } }
步骤2:定义自定义异常类
继承AuthenticationException,携带自定义错误码、描述和HTTP状态码:
public class CustomOAuth2AuthException extends AuthenticationException { private final String errorCode; private final int httpStatus; public CustomOAuth2AuthException(String errorCode, String message, int httpStatus) { super(message); this.errorCode = errorCode; this.httpStatus = httpStatus; } // Getter方法 public String getErrorCode() { return errorCode; } public int getHttpStatus() { return httpStatus; } }
步骤3:注册自定义AuthenticationProvider
替换默认的提供者,确保自定义逻辑生效:
@Configuration public class AuthServerConfig { @Bean public OAuth2AuthorizationCodeAuthenticationProvider customAuthCodeProvider( OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) { return new CustomAuthorizationCodeAuthenticationProvider(authorizationService, tokenGenerator); } }
步骤4:添加异常捕获Filter
通过Filter捕获自定义异常,直接写入响应体并设置状态码:
@Component @Order(Ordered.HIGHEST_PRECEDENCE) public class OAuth2ExceptionHandlerFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { try { chain.doFilter(request, response); } catch (CustomOAuth2AuthException e) { // 设置响应参数 response.setStatus(e.getHttpStatus()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setCharacterEncoding(StandardCharsets.UTF_8.name()); // 构造自定义响应体 Map<String, Object> errorBody = new HashMap<>(); errorBody.put("error", e.getErrorCode()); errorBody.put("error_description", e.getMessage()); // 可按需添加其他字段 new ObjectMapper().writeValue(response.getWriter(), errorBody); } } // 仅对/oauth2/token端点生效 @Override protected boolean shouldNotFilter(HttpServletRequest request) { return !"/oauth2/token".equals(request.getRequestURI()) || !"POST".equals(request.getMethod()); } }
方案2:自定义TokenEndpointFilter替换默认实现
如果需要完全控制端点的异常处理逻辑,可以复制OAuth2TokenEndpointFilter的源码,修改其中的authenticationFailureHandler为自定义实现,再注册到容器中替换默认Filter。注意该方案存在版本兼容性风险,需同步框架源码更新。
内容的提问来源于stack exchange,提问作者Kafer
相关产品推荐
相关产品推荐

