场景
在前后端分离的项目中,一般后端返回给前端的格式是一个固定的json格式。
在这个前提下,spring security oauth 生成access token的请求/auth/token的返回内容就需要自定义
原返回值
我们希望使用我们自己固定的json格式
需求
我们的BaseResponse类
public class BaseResponse {
private String errorcode;
private String value;
public String getErrorcode() {
return errorcode;
}
public void setErrorcode(String errorcode) {
this.errorcode = errorcode;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Response类
@Data
public class Response extends BaseResponse{
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
解决方案
先看源码,这些内容是如何返回的
org.springframework.security.oauth2.provider.endpoint.TokenEndpoint#postAccessToken
return new ResponseEntity<OAuth2AccessToken>(accessToken, headers, HttpStatus.OK);
那么我们的思路是写一个切面,将这个ResponseEntity进行重新组织就可以了。
步骤
1. 定义一个Serializer
public class ResponseSerializer extends StdSerializer<Response> {
public ResponseSerializer() {
super(Response.class);
}
@Override
public void serialize(Response value, JsonGenerator gen, SerializerProvider provider) throws IOException {
OAuth2AccessToken oAuth2AccessToken = (OAuth2AccessToken) value.getData();
gen.writeStartObject();
gen.writeStringField("errorcode", value.getErrorcode());
gen.writeStringField("value", value.getValue());
gen.writeObjectFieldStart("data");
gen.writeStringField("access_token", oAuth2AccessToken.getValue());
gen.writeStringField("token_type", oAuth2AccessToken.getTokenType());
gen.writeStringField("refresh_token", oAuth2AccessToken.getRefreshToken().getValue());
gen.writeNumberField("expires_in",oAuth2AccessToken.getExpiresIn());
gen.writeStringField("scope",oAuth2AccessToken.getScope().toString());
gen.writeStringField("company",oAuth2AccessToken.getAdditionalInformation().get("company").toString());
gen.writeStringField("jti",oAuth2AccessToken.getAdditionalInformation().get("jti").toString());
gen.writeEndObject();
gen.writeEndObject();
}
}
2. 给Response类加入@JsonSerializer注解
@JsonSerialize(using = ResponseSerializer.class)
@Data
public class Response extends BaseResponse{
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
3. 写一个切面来改变返回值
@Component
@Aspect
public class AuthTokenAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
/// @Around是可以改变controller返回值的
@Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
// 放行
Response response = new Response();
Object proceed = pjp.proceed();
if (proceed != null) {
ResponseEntity<OAuth2AccessToken> responseEntity = (ResponseEntity<OAuth2AccessToken>)proceed;
OAuth2AccessToken body = responseEntity.getBody();
if (responseEntity.getStatusCode().is2xxSuccessful()) {
response.setErrorcode(ErrorCode.OK.value);
response.setValue(ErrorCode.OK.memo);
response.setData(body);
} else {
logger.error("error:{}", responseEntity.getStatusCode().toString());
response.setErrorcode(ErrorCode.ERROR.value);
response.setValue("获取授权码失败");
}
}
return ResponseEntity
.status(200)
.body(response);
}
}
最终的效果