个性化token 背景
上一篇文章 《Spring Security OAuth 个性化token(一)》有提到,oauth2.0 接口默认返回的报文格式如下:
{
\"access_token\": \"e6669cdf-b6cd-43fe-af5c-f91a65041382\",
\"token_type\": \"bearer\",
\"refresh_token\": \"da91294d-446c-4a89-bdcf-88aee15a75e8\",
\"expires_in\": 43199,
\"scope\": \"server\"
}
通过上篇文章我们已经可以扩展增加部分业务字段。
{
\"access_token\":\"a6f3b6d6-93e6-4eb8-a97d-3ae72240a7b0\",
\"token_type\":\"bearer\",
\"refresh_token\":\"710ab162-a482-41cd-8bad-26456af38e4f\",
\"expires_in\":42396,
\"scope\":\"server\",
\"tenant_id\":1,
\"license\":\"made by pigx\",
\"dept_id\":1,
\"user_id\":1,
\"username\":\"admin\"
}
「在一些场景下我们需要自定义一下返回报文的格式,例如pig 使用R 对象返回,全部包含code业务码信息」
{
\"code\":1,
\"msg\":\"\",
\"data\":{
\"access_token\":\"e6669cdf-b6cd-43fe-af5c-f91a65041382\",
\"token_type\":\"bearer\",
\"refresh_token\":\"da91294d-446c-4a89-bdcf-88aee15a75e8\",
\"expires_in\":43199,
\"scope\":\"server\"
}
}
方法一:HandlerMethodReturnValueHandler
- 顾名思义这是 Spring MVC 提供给我们修改方法返回值的接口
public class FormatterToken implements HandlerMethodReturnValueHandler {
private static final String POST_ACCESS_TOKEN = \"postAccessToken\";
@Override
public boolean supportsReturnType(MethodParameter returnType) {
// 判断方法名是否是 oauth2 的token 接口,是就处理
return POST_ACCESS_TOKEN.equals(Objects
.requireNonNull(returnType.getMethod()).getName());
}
// 获取到返回值然后使用 R对象统一包装
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer container, NativeWebRequest request) throws Exception {
ResponseEntity<OAuth2AccessToken> responseEntity = (ResponseEntity) returnValue;
OAuth2AccessToken body = responseEntity.getBody();
HttpServletResponse response = request.getNativeResponse(HttpServletResponse.class);
assert response != null;
WebUtils.renderJson(response, R.ok(body));
}
}
- 注入FormatterToken,一定要这么处理,不要直接使用 MVCconfig 注入,保证此Handler比 SpringMVC 默认的提前执行。
public class FormatterTokenAutoConfiguration implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
@Override
public void afterPropertiesSet() {
RequestMappingHandlerAdapter handlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);
List<HandlerMethodReturnValueHandler> returnValueHandlers = handlerAdapter.getReturnValueHandlers();
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<>();
newHandlers.add(new FormatterToken());
assert returnValueHandlers != null;
newHandlers.addAll(returnValueHandlers);
handlerAdapter.setReturnValueHandlers(newHandlers);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
方法二:aop 拦截增强 /oauth/token 接口
@Around(\"execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))\")
public Object handlePostAccessTokenMethod(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取原有值,进行包装返回
Object proceed = joinPoint.proceed();
ResponseEntity<OAuth2AccessToken> responseEntity = (ResponseEntity<OAuth2AccessToken>) proceed;
OAuth2AccessToken body = responseEntity.getBody();
return ResponseEntity
.status(HttpStatus.OK)
.body(R.ok(body));
}
}
总结
实际项目中不建议修改此接口的访问格式,不兼容oauth2协议 导致其他组件不能正常使用 例如
- swagger 自带的认证授权
- 其他网关组件自带的oauth2