很多场景下后端接口返回的数据格式是统一的,这样统一标准对前后端开发人员都是很友好的

Spring Security Oauth2在登录或鉴权失败时默认会返回的格式跟项目制定的标准返回格式不一致,且描述信息较少,因此需要定制Spring Security Oauth2的返回格式

具体实现如下:

1 自定义OAuth2Exception

首先通过继承OAuth2Exception自定义异常类,并指定JSON序列化方式

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 自定义OauthException
*
* @author tangyi
* @date 2020/2/29 14:12
*/
@JsonSerialize(using = CustomOauthExceptionSerializer.class)
public class CustomOauthException extends OAuth2Exception {
public CustomOauthException(String msg) {
super(msg);
}
}

2 自定义JSON序列化

注解@JsonSerialize(using = CustomOauthExceptionSerializer.class)表示响应请求是用CustomOauthExceptionSerializer序列化CustomOauthExceptionCustomOauthExceptionSerializer的逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 自定义OauthException Serializer,定制异常返回结果
*
* @author tangyi
* @date 2020/2/29 14:12
*/
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> {

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

@Override
public void serialize(CustomOauthException e, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField("code", e.getHttpErrorCode());
jsonGenerator.writeStringField("msg", e.getMessage());
jsonGenerator.writeObjectField("data", e.getOAuth2ErrorCode());
if (e.getAdditionalInformation() != null) {
for (Map.Entry<String, String> entry : e.getAdditionalInformation().entrySet()) {
jsonGenerator.writeStringField(entry.getKey(), entry.getValue());
}
}
jsonGenerator.writeEndObject();
}
}

OAuth2Exception经过CustomOauthExceptionSerializer序列化后的结果:

1
2
3
4
5
{
"code":400,
"msg":"用户名或密码错误",
"data":"invalid_request"
}

3 配置AuthorizationServerEndpointsConfigurer

通过配置AuthorizationServerEndpointsConfigurerexceptionTranslator指定异常转换器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 授权服务器配置
*
* @author tangyi
* @date 2019-03-14 11:40
*/
@Configuration
public class CustomAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
...

/**
* 配置TokenStore、Token增强、认证管理器以及异常处理
*
* @param endpoints endpoints
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
// 将token存储到redis
.tokenStore(tokenStore())
// token增强
.tokenEnhancer(jwtTokenEnhancer())
// 异常转换
.exceptionTranslator(webResponseExceptionTranslator());
}

@Bean
@Lazy
public WebResponseExceptionTranslator<OAuth2Exception> webResponseExceptionTranslator() {
return new DefaultWebResponseExceptionTranslator() {
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
if (e instanceof OAuth2Exception) {
OAuth2Exception exception = (OAuth2Exception) e;
// 转换返回结果
return ResponseEntity.status(exception.getHttpErrorCode()).body(new CustomOauthException(e.getMessage()));
} else {
throw e;
}
}
};
}
...
}

4 总结

主要原理是扩展Spring Security Oauth2ExceptionTranslator,指定异常信息的序列化逻辑

自定义之前的格式:

1
2
3
4
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}

自定义返回格式后的结果:

1
2
3
4
5
{
"code":400,
"msg":"用户名或密码错误",
"data":"invalid_request"
}

完整源码: