Передача объектов от перехватчиков сервера в функции - PullRequest
0 голосов
/ 25 февраля 2019

Я создал простой перехватчик сервера, который извлекает пользователя на основе токена JWT.

Но теперь я хотел бы сделать его доступным для всех методов моих служб.

НаСейчас я использую декораторы.Но я бы не хотел украшать все методы.На всякий случай украшай только те, которые не нужны пользователю.

Кто-нибудь может подсказать мне?

вот мой код:

class AuthInterceptor(grpc.ServerInterceptor):
"""Authorization Interceptor"""

def __init__(self, loader):
    self._loader = loader

def intercept_service(self, continuation, handler_call_details):
    # Authenticate if we not requesting token.
    if not handler_call_details.method.endswith('GetToken'):
        # My Authentication class.
        auth = EosJWTAuth()
        # Authenticate using the headers tokens to get the user.
        user = auth.authenticate(
            dict(handler_call_details.invocation_metadata))[0]

        # Do something here to pass the authenticated user to the functions.

    cont = continuation(handler_call_details)
    return cont

И я хотел бы, чтобы мои методы могли получить доступ к пользователю таким способом.

class UserService(BaseService, users_pb2_grpc.UserServicer):
"""User service."""

def get_age(self, request, context):
    """Get user's age"""
    user = context.get_user()
    # or user = context.user 
    # or user = self.user 
    # os user = request.get_user() 
    return pb.UserInfo(name=user.name, age=user.age)

1 Ответ

0 голосов
/ 27 февраля 2019

Это общая потребность для веб-серверов, и было бы неплохо добавить декораторы к обработчикам, чтобы явно установить требования для аутентификации / авторизации.Это помогает удобочитаемости и снижает общую сложность.

Однако здесь есть обходной путь для решения вашего вопроса.Он использует метакласс Python для автоматического декорирования каждого метода обслуживающего устройства.

import grpc
import functools
import six

def auth_decorator(func):
    @functools.wraps(func)
    def wrapper(request, context):
        if not func.__name__.endswith('GetToken'):
            auth = FooAuthClass()
            try:
                user = auth.authenticate(
                    dict(context.invocation_metadata)
                )[0]
                request.user = user
            except UserNotFound:
                context.abort(
                    grpc.StatusCode.UNAUTHENTICATED,
                    'Permission denied.',
                )
        return func(request, context)

    return wrapper

class AuthMeta:

    def __new__(self, class_name, bases, namespace):
        for key, value in list(namespace.items()):
            if callable(value):
                namespace[key] = auth_decorator(value)
        return type.__new__(self, class_name, bases, namespace)

class BusinessServer(FooServicer, six.with_metaclass(AuthMeta)):

    def LogicA(self, request, context):
        # request.user accessible
        ...

    def LogicGetToken(self, request, context):
        # request.user not accessible
        ...
...