Skip to content

12. 使用HttpServerFilter重构边缘服务统一认证和日志扩展(0.0.9)

zhengyangyong edited this page Jul 16, 2018 · 1 revision

ServiceComb Java Chassis针对Http请求提供了一套内置的Filter机制:

接口名 描述
org.apache.servicecomb.common.rest.filter.HttpServerFilter Producer端接受Http请求扩展
org.apache.servicecomb.common.rest.filter.HttpClientFilter Consumer端发起Http请求扩展

因此在边缘服务中的EdgeFilter可以使用这套内置机制中的org.apache.servicecomb.common.rest.filter.HttpServerFilter替换,实现起来更为简单。

提示:内置的Filter机制是全异步的,因此不需要做异步化处理。

重构代码

认证AuthenticationFilter

public class AuthenticationFilter implements HttpServerFilter {

  private final RestTemplate template = RestTemplateBuilder.create();

  private static final String USER_SERVICE_NAME = "user-service";

  public static final String EDGE_AUTHENTICATION_NAME = "edge-authentication-name";

  private static final Set<String> NOT_REQUIRED_VERIFICATION_USER_SERVICE_METHODS = new HashSet<>(
      Arrays.asList("login", "logon", "validate"));

  @Override
  public int getOrder() {
    return 0;
  }

  @Override
  public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx httpServletRequestEx) {
    if (isInvocationNeedValidate(invocation.getMicroserviceName(), invocation.getOperationName())) {
      String token = httpServletRequestEx.getHeader(AUTHORIZATION);
      if (StringUtils.isNotEmpty(token)) {
        String userName = template
            .getForObject("cse://" + USER_SERVICE_NAME + "/validate?token={token}", String.class, token);
        if (StringUtils.isNotEmpty(userName)) {
          //Add header
          invocation.getContext().put(EDGE_AUTHENTICATION_NAME, userName);
        } else {
          return Response
              .failResp(new InvocationException(Status.UNAUTHORIZED, "authentication failed, invalid token"));
        }
      } else {
        return Response.failResp(
            new InvocationException(Status.UNAUTHORIZED, "authentication failed, missing AUTHORIZATION header"));
      }
    }
    return null;
  }

  private boolean isInvocationNeedValidate(String serviceName, String operationPath) {
    if (USER_SERVICE_NAME.equals(serviceName)) {
      for (String method : NOT_REQUIRED_VERIFICATION_USER_SERVICE_METHODS) {
        if (operationPath.startsWith(method)) {
          return false;
        }
      }
    }
    return true;
  }
}

日志LogFilter

public class LogFilter implements HttpServerFilter {

  private static final String LOG_SERVICE_NAME = "infrastructure:log-service";

  private final CseAsyncRestTemplate restTemplate = new CseAsyncRestTemplate();

  @Override
  public int getOrder() {
    return 1;
  }

  @Override
  public Response afterReceiveRequest(Invocation invocation, HttpServletRequestEx httpServletRequestEx) {
    String userName = invocation.getContext().get(AuthenticationFilter.EDGE_AUTHENTICATION_NAME);
    if (StringUtils.isNotEmpty(userName)) {
      HttpEntity<LogDTO> request = new HttpEntity<>(
          new LogDTO(userName, invocation.getMicroserviceName(), invocation.getOperationName(), new Date()));
      try {
        restTemplate.postForEntity("cse://" + LOG_SERVICE_NAME + "/record", request, Boolean.class);
      } catch (Exception ignored) {
      }
    }
    return null;
  }
}

加载Filter

resource\META-INF\services目录下,新建org.apache.servicecomb.common.rest.filter.HttpServerFilter文件,在其中添加:

org.apache.servicecomb.scaffold.edge.filter.AuthenticationFilter
org.apache.servicecomb.scaffold.edge.filter.LogFilter

验证

Edge服务启动后,能够在启动日志中查看到Filter成功加载的信息:

2018-07-16 10:54:11,964 [INFO] Found SPI service org.apache.servicecomb.common.rest.filter.HttpServerFilter, count=4. org.apache.servicecomb.foundation.common.utils.SPIServiceUtils.loadSortedService(SPIServiceUtils.java:76)
2018-07-16 10:54:11,965 [INFO]   0. org.apache.servicecomb.common.rest.filter.inner.ServerRestArgsFilter. org.apache.servicecomb.foundation.common.utils.SPIServiceUtils.loadSortedService(SPIServiceUtils.java:79)
2018-07-16 10:54:11,965 [INFO]   1. org.apache.servicecomb.scaffold.edge.filter.AuthenticationFilter. org.apache.servicecomb.foundation.common.utils.SPIServiceUtils.loadSortedService(SPIServiceUtils.java:79)
2018-07-16 10:54:11,965 [INFO]   2. org.apache.servicecomb.common.rest.filter.tracing.TracingFilter. org.apache.servicecomb.foundation.common.utils.SPIServiceUtils.loadSortedService(SPIServiceUtils.java:79)
2018-07-16 10:54:11,965 [INFO]   3. org.apache.servicecomb.scaffold.edge.filter.LogFilter. org.apache.servicecomb.foundation.common.utils.SPIServiceUtils.loadSortedService(SPIServiceUtils.java:79)