在第一个 gRPC 拦截器中,在第二个 gRPC 拦截器之前访问消息请求的信息。

3
我的问题类似于帖子,但它似乎已经过时并且不活跃,因此我在这里重新发布。
基本上,我的用例很奇怪,我需要将授权令牌发送到gRPC请求正文中(而不是标题中)。 我的想法是使用一组拦截器,其中第一个将读取gRPC消息并根据消息中的令牌设置 Authorization 标头。 第二个拦截器将是常规授权拦截器,并将读取刚刚设置为授权标头的令牌。 我希望以这种方式进行操作,因为这样可以重用已存在的授权拦截器代码。
我按如下方式调用拦截器:
ServerInterceptors.intercept(
    new MyResource(resource),
    new SecondInterceptorHeaderAuthorization(),
    new FirstInterceptorReadTokenFromMessageBody()
)

FirstInterceptorReadTokenFromMessageBody() 的函数大致如下:

public class FirstInterceptorReadTokenFromMessageBody implements ServerInterceptor {

  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {


    return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(
            next.startCall(call, headers)) {
          @Override
          public void onMessage(ReqT request) {

            var value = ((MyRequest) request).getAuthorization();
            Metadata.Key<String> key =
                Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER);
            headers.put(key, value);

            super.onMessage(request);
          }
        };
  }
}

还有 SecondInterceptorHeaderAuthorization() 拦截器:

public class SecondInterceptorHeaderAuthorization implements ServerInterceptor {

  public <ReqT, RespT> Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
      .... handle authorization here
}

拦截器按照相反的顺序被正确触发;请求最终由SecondInterceptorHeaderAuthorization()处理,首先是头部授权,然后是FirstInterceptorReadTokenFromMessageBody()读取消息体。如何让消息拦截器先运行,然后是头部拦截器?这是否可能?我是否错过了解决此问题的更好方法?


我认为你应该将头信息放在客户端的元数据中,就像traceId一样,而不是放在消息中,这样你只需要一个拦截器来处理授权,并可以直接从头信息中读取。 - HelloWood
很想这样做,但是请求经过的代理正在剥离所有头信息。我认为我已经找到了解决方案。等我有更多时间时,我会写下来。 - walshbm15
1个回答

1

我搞定了。基本上,我按照这里线程中所描述的做法进行操作。

现在我的FirstInterceptorReadTokenFromMessageBody类看起来是这样的:

public class FirstInterceptorReadTokenFromMessageBody implements ServerInterceptor {
  @Override
  public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
      ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {

    final Listener<ReqT> authorizationLookUpCallListener =
        new ForwardingServerCallListener<ReqT>() {
          private final Listener<ReqT> NOOP = new Listener<ReqT>() {};
          private Listener<ReqT> delegate = NOOP;

          @Override
          protected Listener<ReqT> delegate() {
            return delegate;
          }

          @Override
          public void onMessage(ReqT message) {
            // ensures that this interceptor only run first
            if (delegate == NOOP) {
              if (message instanceof MyRequest) {
                String auth_token = ((MyRequest) message).getAuthToken();
                headers.put(
                    Metadata.Key.of("my-auth-token-header", Metadata.ASCII_STRING_MARSHALLER),
                    auth_token);
              }
              delegate = next.startCall(call, headers);
            }
            super.onMessage(message);
          }
        };

    ServerCallHandler<ReqT, RespT> handler =
        (call1, headers1) -> {
          call1.request(1);
          return authorizationLookUpCallListener;
        };

    return handler.startCall(call, headers);
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接