spring security oauth2 自定义invalid_token返回体

框架

springboot+security+oauth2

问题

默认token过期的返回格式是这样的

{
  "error": "invalid_token",
  "error_description": "Invalid access token: XXXXXXXXXXXXXXXXXXXXXXX"
}

通常情况下,这与我们自己定义的数据返回的response格式不统一,不方便客户端做统一处理。如果要改成自己的格式的,需要怎么做呢?

效果

修改格式前

{
  "error": "invalid_token",
  "error_description": "Invalid access token: XXXXXXXXXXXXXXXXXXXXXXX"
}

修改格式后

{
  "errCode": -1,
  "errorMsg": "登陆凭证过期"
}
处理流程

1.新建或者打开security的继承自ResourceServerConfigurerAdapter的配置类(一般情况都已经创建了这个类),添加如下代码

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
        authenticationEntryPoint.setExceptionTranslator(new CustomExceptionTranslator());
        resources.authenticationEntryPoint(authenticationEntryPoint);
    }

2.创建CustomExceptionTranslator类

public class CustomExceptionTranslator extends DefaultWebResponseExceptionTranslator {

    @Override
    public ResponseEntity translate(Exception e) throws Exception {
        ResponseEntity translate = super.translate(e);
        OAuth2Exception body = translate.getBody();
        CustomOauthException customOauthException = new CustomOauthException(body.getMessage(),body.getOAuth2ErrorCode(),
                body.getHttpErrorCode());
        ResponseEntity response = new ResponseEntity<>(customOauthException, translate.getHeaders(),
                translate.getStatusCode());
        return response;
    }

}

3.创建CustomOauthException类

@JsonSerialize(using = CustomOauthExceptionSerializer.class)
public class CustomOauthException extends OAuth2Exception {

    private String oAuth2ErrorCode;

    private int httpErrorCode;

    public CustomOauthException(String msg, String oAuth2ErrorCode, int httpErrorCode) {
        super(msg);
        this.oAuth2ErrorCode = oAuth2ErrorCode;
        this.httpErrorCode = httpErrorCode;
    }

    public String getoAuth2ErrorCode() {
        return oAuth2ErrorCode;
    }

    public int getHttpErrorCode() {
        return httpErrorCode;
    }
}

4.创建CustomOauthException类

public class CustomOauthExceptionSerializer extends StdSerializer {

    public CustomOauthExceptionSerializer() {
        super(CustomOauthException.class);
    }

    @Override
    public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        //value内容适当的做一些错误类型判断
        gen.writeStartObject();
        gen.writeObjectField("errCode",-1);
        gen.writeObjectField("errorMsg","登陆凭证过期");
        gen.writeEndObject();
    }
}

打完收工
参考了这篇文章

参考源代码分析一波原因

由于我用的生成token的类是JdbcTokenStore

    @Bean
    public JdbcTokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

所以打开JdbcTokenStore类,可以看到有很多跟查询token相关的方法,逐个断点,尝试一个无效的token,最终断点命中在readAccessToken函数


JdbcTokenStore.readAccessToken

果不其然,断点处会报错,并且这个函数最终accessToken会返回null。token_invalid的错误信息写入response的代码这里没有,说明在这个函数更上层,往外找到DefaultTokenServices.loadAuthentication


DefaultTokenServices.loadAuthentication

同理,经过几层的查看,最终找到OAuth2AuthenticationProcessingFilter.doFilter,可以看到这里在操作response


OAuth2AuthenticationProcessingFilter.doFilter

实际上这里框出来的authenticationEntryPoint对象就是我们前面提到的解决方案中,被我们替换成自定义ExceptionTranslator的authenticationEntryPoint,再看一下原始的commence方法里跟我们的操作response相关的代码做了些什么,debug进去,来到DefaultWebResponseExceptionTranslator.translate

translate+handleOAuth2Exception

translate方法里面一顿操作,最终会返回一个ResponseEntity,看一下ResponseEntity接受的三个参数,分别是一个会被转成json的对象,headers,http状态码。这三个东西熟悉http请求的就感觉很亲切了。也就是说我不管这里这一大坨代码做了什么,只要我按照我自己的要求返回一个ResponseEntity就可以。于是乎就有了开头解决方法中的替换成自己定义的ExceptionTranslator的解决思路。

现在框架有很多这种设计模式中的策略模式的设计来方便开发人员自己定义执行方法。类似DefaultXXXXXX的类,基本上都可以通过自己创建自定义对象来实现多样化的需求。当然我也是先百度了解决方案之后,再去看原因的,多看看原理,万一以后百度没作业给你抄的时候,你自己也能通过阅读代码,找到方法。

你可能感兴趣的:(spring security oauth2 自定义invalid_token返回体)