Spring Cloud实战 | 第十篇: 授权服务器ljf-auth 实现Bad client credentials异常自定义信息返回
分析: 之前两种异常方式都可以通过全局异常处理器捕获,且@RestControllerAdvice只能捕获Controller的异常。 客户端认证的异常则是发生在过滤器filter上,此时还没进入DispatcherServlet请求处理流程,便无法通过全局异常处理器捕获。
1、添加CustomAuthenticationEntryPoint 设置异常响应数据格式
/**
* @Auther: lijinfeng
* @Date: 2021/12/22
* @Description 如果直接通过AuthenticationEntryPoint是无法自定义返回的信息,我们需要重写过滤器ClientCredentialsTokenEndpointFilter
*/
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.setStatus(HttpStatus.OK.value());
Result r = Result.error(ResultEnum.ERROR_AuthenticationEntryPoint, "client_id或client_secret错误");
response.setHeader("Content-Type", "application/json;charset=utf-8");
response.getWriter().print(JSONUtil.toJsonStr(r));
response.getWriter().flush();
}
}
2、添加CustomClientCredentialsTokenEndpointFilter 达到替换AuthenticationEntryPoint的目的
**
* @Auther: lijinfeng
* @Date: 2021/12/22
* @Description 描述: 如果直接通过AuthenticationEntryPoint是无法自定义返回的信息,我们需要重写过滤器ClientCredentialsTokenEndpointFilter。
*/
public class CustomClientCredentialsTokenEndpointFilter extends ClientCredentialsTokenEndpointFilter {
private AuthorizationServerSecurityConfigurer configurer;
private AuthenticationEntryPoint authenticationEntryPoint;
public CustomClientCredentialsTokenEndpointFilter(AuthorizationServerSecurityConfigurer configurer) {
this.configurer = configurer;
}
@Override
public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
// 把父类的干掉
super.setAuthenticationEntryPoint(null);
this.authenticationEntryPoint = authenticationEntryPoint;
}
@Override
protected AuthenticationManager getAuthenticationManager() {
return configurer.and().getSharedObject(AuthenticationManager.class);
}
@Override
public void afterPropertiesSet() {
setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
authenticationEntryPoint.commence(httpServletRequest, httpServletResponse, e);
}
});
setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
// 无操作-仅允许过滤器链继续到令牌端点
}
});
}
}
3、修改AuthorizationServerSecurityConfigurer,注入上面的修改
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
CustomClientCredentialsTokenEndpointFilter endpointFilter = new CustomClientCredentialsTokenEndpointFilter(security);
endpointFilter.afterPropertiesSet();
endpointFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
security
// 允许所有人请求令牌
.tokenKeyAccess("permitAll()")
// 已验证的客户端才能请求check_token端点
.checkTokenAccess("isAuthenticated()")
//实现Bad client credentials异常自定义信息返回 注意:security不需要在调用allowFormAuthenticationForClients方法
.addTokenEndpointAuthenticationFilter(endpointFilter)
// ~ 允许客户端表单验证
// 只对 /oauth/token 端点有响应
// 该设定会开启一个在 BasicAuthenticationFilter 前执行的过滤器, 名为 ClientCredentialsTokenEndpointFilter. 这个过滤器
// 会尝试从请求参数中获取 client_id 和 client_secret 以完成认证
// .allowFormAuthenticationForClients()
;
}
4、请求报自定义异常