我创建了一个简单的服务器拦截器,该服务器拦截器基于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)
答案 0 :(得分:1)
这是对Web服务器的普遍需求,将装饰器添加到处理程序中以显式设置身份验证/授权要求是一个好主意。它有助于提高可读性,并降低整体复杂性。
但是,这里有一个解决方法来解决您的问题。它使用Python元类自动装饰每个servicer方法。
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
...