最近使用spring security oauth2 做开放平台,想要返回统一的返回值格式,做的过程中发现相当麻烦,好在效果总算达到了,在这里总结一下,希望能帮助到遇到相同问题的同学。实现方式并不完美,如果你有更好的方式或发现文内有问题,希望不吝赐教。
Oauth2 协议有4种认证方式,项目里用到了客户端模式和密码模式,都是依托于spring security oauth2。开发过程中发现框架原生响应的格式一般如下:
{
"error": "invalid_grant",
"error_description": "Bad credentials"
}
为了调用方的便利、保证平台的统一性,希望统一响应的格式,最起码有code和友好的提示信息message,比如:
{
"code": 401101,
"message": "客户端认证失败"
}
开发过程中需要对如下几种请求统一响应值格式
客户端/密码模式获取token失败——参数中未携带client_id、参数中client_id或client_secret不正确
密码模式获取token失败——参数中userName或password不正确
资源接口请求失败——未带token、token过期、token有效但资源权限不足
正常的oauth/token的响应体结构——重写原token格式
客户端/密码模式获取token失败——参数中未携带client_id、参数中client_id或client_secret不正确
密码模式获取token时需要先验证客户端、再验证用户,因此可以合这两种情况,由于密码模式获取token过程中也需要验证client,且验证逻辑与客户端模式相同,都会使用下面的方式。
这里有一个前提是client验证必须是basic auth方式,即在请求头中设置Authorization参数,将client_id和client_secret以:间隔进行拼接,然后将拼接后的字符串使用 BASE64 编码与Basic拼接,可生成 Authorization 参数的值。还有一个传参方式是form形式,form形式无法定义返回值格式,框架里写死了。
自定义一个OncePerRequestFilter子类,在filter中重写认证逻辑,再将其注入到AuthorizationServerSecurityConfigurer
/**
* basic auth 方式client认证过滤器
* 置于{@link org.springframework.security.web.authentication.www.BasicAuthenticationFilter}之前,
* 以实现客户端信息不全、认证失败时返回自定义响应信息
*
* @author zhangjw
* @version 1.0
*/
@Component
@Slf4j
public class CustomBasicAuthenticationFilter extends OncePerRequestFilter {
@Resource
private ClientDetailsService clientDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (!request.getRequestURI().contains("/oauth/token")) {
filterChain.doFilter(request, response);
return;
}
String[] clientDetails = this.isHasClientDetails(request);
// 客户端信息缺失
if (clientDetails == null) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
OpenApiResp resp = OpenApiResp.build(OpenApiRespEnum.OAUTH_GET_TOKEN_FAIL_CLIENT_MISSING);
response.getWriter().write(JsonUtil.beanToJson(resp));
return;
}
try {
this.handle(request, response, clientDetails, filterChain);
} catch (CustomOauthException c