OAuth в gRPC с использованием Java

Я пытаюсь реализовать OAuth2 между моим сервером gRPC и клиентскими приложениями с помощью перехватчиков, выполнив следующие действия:

  1. клиентское приложение вызывает метод gRPC сервера
  2. серверное приложение отвечает статусом UNAUTHENTICATED и redirect-url в заголовках
  3. клиент получает redirect-url, использует его для доступа к серверу авторизации и, наконец, получает access_token
  4. клиентское приложение вызывает метод gRPC сервера (на этот раз с access_token)

Однако шаг 4 кажется невозможным за один вызов, поскольку транзакция уже закрыта на шаге 2. Есть ли способ выполнить эти 4 шага всего за один вызов службы gRPC?

Вот мой класс 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);
            }
        };
    }
}

person Julius Delfino    schedule 03.05.2018    source источник
comment
Привет, я задал этот вопрос об учетной записи grpc-java на GitHub, вот ссылка github. com / grpc / grpc-java / issues / 6638   -  person OhhhThatVarun    schedule 24.01.2020
comment
Вот ответ на этот вопрос на github. github.com/grpc/grpc-java/issues/5856#issuecomment- 511077021   -  person OhhhThatVarun    schedule 28.01.2020


Ответы (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;
    }
}
person Julius Delfino    schedule 04.05.2018