gRPC: добавить свойства в контекст из декоратора или ServiceInterceptor - PullRequest
0 голосов
/ 28 октября 2019

Я использую декораторы для аутентификации. Если это удастся, я хочу расширить context с дополнительной информацией. Как это может быть достигнуто?

@require_authorization
def test(request, context):
    <...>

def require_authorization(func):
    def wrapper(request, context):
        <...How can I extend the context here?...>
        return func(request, context)
    return wrapper

Я также попробовал ServiceInterceptor, но тоже застрял в этом маршруте:

class Interceptor(grpc.ServerInterceptor):

    def intercept_service(self, continuation, handler_call_details):
        <...Can I extend the metadata here somehow?...>
        return continuation(handler_call_details)

server = grpc.server(
            futures.ThreadPoolExecutor(max_workers=10),
            interceptors=(Interceptor(),),
            )

Обходной путь с декоратором

На основании ответа Лиди Чжэн (спасибо!) Я использую следующий декоратор. Вероятно, наиболее раздражающим аспектом является предоставление реализаций для всех методов абстрактного базового класса. Поскольку это плохо документировано, я получил их от источника.

class AuthServicerContext(grpc.ServicerContext):

    def __init__(self, context: grpc.ServicerContext, func_name):
        self._original_context = context
        meta = dict(context.invocation_metadata())

    def abort(self, code, details):
        self._original_context.abort(code, details)

    def abort_with_status(self, status):
        self._original_context.abort_with_status(status)

    def add_callback(self, callback):
        self._original_context.add_callback(callback)

    def auth_context(self):
        self._original_context.auth_context()

    def cancel(self):
        self._original_context.cancel()

    def invocation_metadata(self):
        self._original_context.invocation_metadata()

    def is_active(self):
        self._original_context.is_active()

    def peer(self):
        self._original_context.peer()

    def peer_identities(self):
        self._original_context.peer_identities()

    def peer_identity_key(self):
        self._original_context.peer_identity_key()

    def send_initial_metadata(self, initial_metadata):
        self._original_context.send_initial_metadata(initial_metadata)

    def set_code(self,code):
        self._original_context.set_code(code)

    def set_details(self, details):
        self._original_context.set_details(details)

    def set_trailing_metadata(self, trailing_metadata):
        self._original_context.abort(trailing_metadata)

    def time_remaining(self):
        self._original_context.time_remaining()

def require_authorization(func):
    def wrapper(self, request, context):
        return func(self, request, AuthServicerContext(context, func.__name__))
    return wrapper

1 Ответ

1 голос
/ 31 октября 2019

К сожалению, добавление свойств к ServicerContext через перехватчик не поддерживается. См. историю перехватчика на стороне сервера.

С другой стороны, использование декораторов для аутентификации возможно:

class MyPowerfulServicerContext(grpc.ServicerContext):
    def __init__(self, original_context: grpc.ServicerContext):
        self._original_context = original_context
        ...Perform authentication with metadata / peer identity / etc.

    def ...Your_extended_functions

    # You can port the invocation  of methods to the original context
    def abort(self, code, details):
        self._original_context.abort(code, details)

    ...



def require_authorization(func):
    def wrapper(request, context):
        return func(request, MyPowerfulServicerContext(context))
    return wrapper

Надеюсь, это полезно для вашегоиспользуйте случай, если я не понял, пожалуйста, оставьте комментарий. Кроме того, не стесняйтесь подавать вопросы на https://github.com/grpc/grpc.

...