关于Oauth2的微服务接口:正常数据和异常数据如何自定义统一的数据格式

在基于Oauth2的微服务项目中,往往希望有统一格式的数据返回,包括以下四种情况:

  • Oauth2异常数据的封装
    {
        "code": 0,
        "message": "请求失败",
        "result": "无效token"
    }  
  • Oauth2正常数据的封装
    {
        "code": 1,
        "message": "请求成功",
        "result": {
            "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
            "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
            "exp": "1596721265802"
        }
    }
  • 接口异常数据的封装
    {
        "code": 0,
        "message": "请求失败",
        "result": "异常信息"
    }
  • 接口正常数据的封装
    {
        "code": 1,
        "message": "请求成功",
        "result": "接口数据"
    } 

针对上述四种情况进行处理:

1.Oauth2异常数据的封装:

是四种情况中相对最为复杂的部分:分为认证服务器的异常信息处理和资源服务器的异常信息处理

1.1认证服务器的异常信息处理(通常是获取token时抛出的异常)

①需要在AuthorizationServerConfigurerAdapter的AuthorizationServerEndpointsConfigurer进行配置

   endpoints.exceptionTranslator(customWebResponseExceptionTranslator)//自定义异常处理
   //配置WebResponseExceptionTranslator自定义异常,并重写translate方法返回自定义Oauth2认证异常信息

②由于在AuthorizationServerEndpointsConfigurer无法重写客户端配置信息异常,需要进行另行处理

 需要在AuthorizationServerConfigurerAdapter的AuthorizationServerSecurityConfigurer进行配置  

   CustomClientCredentialsTokenEndpointFilter endpointFilter = new CustomClientCredentialsTokenEndpointFilter(security);
   endpointFilter.afterPropertiesSet();
   endpointFilter.setAuthenticationEntryPoint(customAuthenticationEntryPoint);
   security.addTokenEndpointAuthenticationFilter(endpointFilter);//自定义异常过滤器和客户端端点过滤器
   //配置ClientCredentialsTokenEndpointFilter自定义过滤器,并加入AuthenticationEntryPoint重写commence方法,自定义返回Oauth2异常信息。

1.2资源服务器的异常信息处理(验证token时抛出的异常):包括认证异常和授权异常的配置

   //在资源服务器ResourceServerConfigurerAdapter的ResourceServerSecurityConfigurer中配置
   resources.authenticationEntryPoint(customAuthExceptionEntryPoint)//认证异常处理类
   resources.accessDeniedHandler(customAccessDeniedHandler)//权限异常处理类

配置认证异常处理AuthenticationEntryPoint,重写commence方法,自定义Oauth2异常信息。

配置授权异常处理AccessDeniedHandler,重写handle方法,自定义Oauth2异常信息。

2.Oauth2正常数据的封装

使用aop重写oauth2的TokenEndpoint.postAccessToken结果

  //类注解@Component和@Aspect
  @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
  //获取原有方法返回值为ResponseEntity<OAuth2AccessToken> responseEntity 
  //将responseEntity 中需要的信息放入map中,返回
  return ResponseEntity.status(HttpStatus.OK).body(map);
  //这里直接返回map,数据格式会在后续统一处理。
  //同样如果需要也可以通过aop重写CheckTokenEndpoint.checkToken

3.接口异常数据和正常数据的封装 

//这里为了方便将异常和数据放在一起进行处理(RestResponse为定义的统一数据类)
  @ControllerAdvice
  public class GlobalExceptionHandler implements ResponseBodyAdvice {
    private ObjectMapper objectMapper = new ObjectMapper();
   //统一异常处理
  @ExceptionHandler(value = Exception.class)
  @ResponseBody
  public RestResponse<Object> exceptionHandler(HttpServletRequest req, Exception e){
  return RestResponse.failure(e.getMessage());
  }

   //统一数据处理
  @Override
  public boolean supports(MethodParameter methodParameter, Class aClass) {
  return true;
  }
  
  @Override
  public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass,
    ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {   
//String类型返回会发生类型转换异常,额外处理     if (o instanceof String) {       try {         serverHttpResponse.getHeaders().set("Content-Type", "application/json;charset=utf-8");         return objectMapper.writeValueAsString(RestResponse.success(o));       } catch (JsonProcessingException e) {         e.printStackTrace();       }     }else if(o instanceof RestResponse){       //原有部分接口已经使用RestResponse包装过,防止重复包装。       return o;     }     //统一数据包装,包括Oauth2的正常数据(Oauth2的异常数据已经直接),Oauth2的异常数据已经直接httpServletResponse.getWriter().write()不需要处理     return RestResponse.success(o);    } }

4.总结

整理总结了在处理基于Oauth2的微服务接口中,正常数据和异常数据自定义统一数据格式的问题。

posted @ 2020-08-06 11:27  Masting  阅读(2353)  评论(0编辑  收藏  举报