Как правильно использовать ThreadLocal в перехватчике GRPC? - PullRequest
0 голосов
/ 01 июля 2019

У нас есть служба gPRC, которая должна установить информацию об аутентификации / идентификации в переменной ThreadLocal в классе, чтобы он мог правильно вызывать другую службу.Служба gPRC получает информацию об аутентификации / идентификации из запроса, поэтому я думаю использовать перехватчик.

Для начала у меня есть некоторый код, выглядящий следующим образом.

public class ImpersonationInterceptor {
    public <ReqT, RespT> interceptCall(
        ServerCall<ReqT, RespT> serverCall, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        Principal principal = ... // get the identify from the request

        AuthContext.setPrincipal(principal); // underneath it uses a ThreadLocal.

        return next.startCall(
            new SimpleForwardingServerCall<>(call) {
                public void close(Status status, Metadata trailers) {
                    AuthContext.setPrincipal(null); // clear the identity
                }
            }
        )
    }
}

Вопросы.

  • Выполнение самого метода службы может не лежать в одном потоке для выполнения перехватчика, верно?
  • Если true, вышеприведенное не сработает, тогда возникает вопрос,Каков канонический способ установить переменную ThreadLocal в мире gRPC?Я знаю, что gRPC поддерживает контекст с 0.12, но в моем случае я должен использовать механизм ThreadLocal AuthContext.

Заранее большое спасибо.

1 Ответ

1 голос
/ 01 июля 2019

Вы должны быть очень осторожны с ThreadLocals для этого типа контекстной информации, потому что вы не хотите случайно использовать неверную идентификационную информацию для клиента.

Каждый обратный вызов от gRPC может происходить в другом потоке, а обратные вызовы для нескольких RPC могут происходить в одном потоке.

Вам необходимо следовать шаблону, подобному Contexts.interceptCall () . Вы должны установить / сбросить после каждого звонка:

public class ImpersonationInterceptor {
  public <ReqT, RespT> interceptCall(
      ServerCall<ReqT, RespT> serverCall, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
    Principal principal = ...;
    AuthContext.setPrincipal(principal);
    try {
      return new WrappingListener<>(next.startCall(call, headers), principal);
    } finally {
      AuthContext.clearPrincipal();
    }
  }

  private static class WrappingListener<ReqT> extends
      ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
    private final Principal principal;

    public WrappingListener(ServerCall.Listener<ReqT> delegate, Principal principal) {
      super(delegate);
      this.principal = principal;
    }

    @Override
    public void onMessage(ReqT message) {
      AuthContext.setPrincipal(principal);
      try {
        super.onMessage(message);
      } finally {
        AuthContext.clearPrincipal();
      }
    }
    ... repeat for each method
  }
}
...