个人认为 Spring Authorization Server 的异常提示目前还不是很完善,很多信息都是简化的信息,很难直观看出根本原因,而且后台还没有打印异常日志(笔者已经提了个issue,寄希望于后续版本能通过日志级别控制异常日志的输出,便于我们开发时调试)。
下文便来先看看核心流程的异常处理。
本文使用 0.3.1 版本
我们知道,客户端认证的核心过滤器是 OAuth2ClientAuthenticationFilter,查看其处理逻辑。

异常处理类为 AuthenticationFailureHandler,实现类是方法引用 this::onAuthenticationFailure


核心类是 OAuth2ErrorHttpMessageConverter

OAuth2ErrorHttpMessageConverter 的核心方法为 writeInternal(...),可以看到,它直接将异常信息写入响应流outputMessage 中,返回给了前端。没有其他处理,后台也就看不了详细异常日志。

我们试下故意写错信息来发送请求,看看响应和日志,如下:


可以看到,异常响应不清晰,日志也没啥有用的内容。如果这不是我们故意写错,根本无法判断哪里出错了。
介于这种情况,我们在开发时调试,可以通过 debug 来查看异常日志了。
OAuth2ClientAuthenticationFilter 的 catch 逻辑块打上断点(以IDEA为例)

ex.printStackTrace();,点击 Evaluate 按钮执行代码。可以在控制台看到日志。

在分析流程时我们可以看到,发生异常时是由 AuthenticationFailureHandler 进行处理的。自然我们可以通过重写该实现来打印异常日志。
默认实现为:OAuth2ClientAuthenticationFilter#authenticationFailureHandler
public class ClientAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final HttpMessageConverter<OAuth2Error> errorHttpResponseConverter = new OAuth2ErrorHttpMessageConverter();
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// 打印异常栈
exception.printStackTrace();
SecurityContextHolder.clearContext();
OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
if (OAuth2ErrorCodes.INVALID_CLIENT.equals(error.getErrorCode())) {
httpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
} else {
httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
}
// We don't want to reveal too much information to the caller so just return the error code
OAuth2Error errorResponse = new OAuth2Error(error.getErrorCode());
this.errorHttpResponseConverter.write(errorResponse, null, httpResponse);
}
}
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); 之后,增加如下配置:http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.clientAuthentication(new Customizer<OAuth2ClientAuthenticationConfigurer>() {
@Override
public void customize(OAuth2ClientAuthenticationConfigurer oAuth2ClientAuthenticationConfigurer) {
oAuth2ClientAuthenticationConfigurer.errorResponseHandler(new ClientAuthenticationFailureHandler());
}
});
搞定。
授权端点的核心过滤器是 OAuth2AuthorizationEndpointFilter。和上文同理,可利用相同的办法打印日志。
令牌颁发的核心过滤器是 OAuth2TokenEndpointFilter。和上文同理,可利用相同的办法打印日志。
异常响应的 error 枚举值:org.springframework.security.oauth2.core.OAuth2ErrorCodes