™技术博客

框架 | 9.OAuth格式化token输出

2021年8月11日

个性化token 背景


oauth2.0 接口默认返回的报文格式如下:

1
2
3
4
5
6
7
{
    "access_token""e6669cdf-b6cd-43fe-af5c-f91a65041382",
    "token_type""bearer",
    "refresh_token""da91294d-446c-4a89-bdcf-88aee15a75e8",
    "expires_in"43199
    "scope""server"
}

可以扩展增加部分业务字段。

1
2
3
4
5
6
7
8
9
10
11
12
{
    "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"
}

在一些场景下我们需要自定义一下返回报文的格式,例如使用R 对象返回,全部包含code业务码信息

1
2
3
4
5
6
7
8
9
10
11
{
    "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"
    }
}

1. 方法一:HandlerMethodReturnValueHandler

顾名思义这是 Spring MVC 提供给我们修改方法返回值的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 默认的提前执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class FormatterTokenAutoConfiguration implements ApplicationContextAwareInitializingBean {
 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;
 }
}

2. 方法二:aop 拦截增强 /oauth/token 接口

1
2
3
4
5
6
7
8
9
10
11
12
@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
      都将失效总体来权衡 弊大于利

扫描二维码,分享此文章