有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用Java在gRPC中实现OAuth

我正在尝试使用拦截器在gRPC服务器和客户端应用程序之间实现OAuth2,步骤如下:

  1. 客户端应用程序调用服务器的gRPC方法
  2. 服务器应用程序以UNAUTHENTICATED状态和头中的redirect-url进行响应
  3. 客户端获得redirect-url,使用它访问授权服务器,最后获得access_token
  4. 客户端应用程序调用服务器的gRPC方法(这次使用access_token

然而,由于交易已经在第2步结束,因此在一次通话中第4步似乎是不可能的。有没有办法在一次gRPC服务呼叫中完成这4个步骤

这是我的ClientInterceptor课程。我指出了代码中的4个步骤(参见代码注释)

public class OAuthClientInterceptor implements ClientInterceptor {

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {

        return new CheckedForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {

            @Override
            public void checkedStart(Listener<RespT> responseListener, Metadata headers) {

                if (redirectUrl != null) {
                    try {
                        //[Step #3] Obtain the access token
                        accessToken = obtainAccessToken(redirectUrl);
                    } catch (ConnectException e) {
                        throw new StatusRuntimeException(Status.UNAUTHENTICATED.withCause(e));
                    }
                }
                if (accessToken != null) {
                    headers.put(Key.of("Authorization",
                        Metadata.ASCII_STRING_MARSHALLER), "Bearer " + accessToken);

                }
                if (recursiveCall) {
                    //[Step #4] PROBLEM: still results to UNAUTHENTICATED
                    next.newCall(method, callOptions).start(responseListener, headers);
                    recursiveCall = false;
                    return;
                }
                OAuthResponseListener<RespT> oAuthRespListener = new OAuthResponseListener(responseListener);
                oAuthRespListener.setUnauthenticatedListener(trailers->{

                    //[Step #2] Obtain the redirect-url
                    redirectUrl = trailers.get(Key.of("redirect-url", Metadata.ASCII_STRING_MARSHALLER));
                    recursiveCall = true;

                    //[Step #3 and 4] Invoke the retrieval of access token and the 2nd call to gRPC method
                    checkedStart(responseListener, headers);
                });
                //[Step #1] Call the gRPC method
                delegate().start(oAuthRespListener, headers);
            }
        };
    }
}

共 (1) 个答案

  1. # 1 楼答案

    我已经解决了这个问题,但我希望找到一些内置的身份验证机制或对blockingStub函数的多次调用来支持这个oAuth流,但没有找到任何

    所以我至少打了两次电话给blockingStub.invokeServerMethod()

    1. 知道它是否还没有通过身份验证,并且能够获得redirect-url
    2. 能够调用invokeServerMethod并将access_token附加到标题

    请注意,我有30个服务器方法,我必须对所有这些方法调用实现相同的步骤。为了尽量减少每个服务器方法的代码重复,我创建了一个RetryUtil类,将为每个服务器方法调用该类。以下是我所做的:

    public class GrpcClient {
    
        public SomeResponse callServerMethod() {
            //invoke the method twice
            return RetryUtil.retry(() -> blockingStub.invokeServerMethod(), 2); 
        }
    }
    
    public class RetryUtil {
    
        public static <T> T retry(Supplier<T> supplier, int retryCount) {
    
            StatusRuntimeException finalEx = null;
            for (int i=0; i<retryCount; i++) {
                try {
                    return supplier.get();
                } catch (StatusRuntimeException e) {
                    if (e.getStatus() != Status.UNAUTHENTICATED) {
                        throw e;
                    }
                    finalEx = e;
                }
            }
            throw finalEx;
        }
    }