python - 在 Django 中使用 Knox Token 从 DRF Token 中的令牌字符串获取用户对象
问题描述
我有与 Django 相关的问题。当每个用户登录页面时,我正在使用 Knox 令牌身份验证为每个用户生成令牌。
现在我想为每个将发送的请求使用该令牌,这样我就可以获得该令牌的相应用户。我def dashboard(request)
还在 Django 中为每个 URL 路由使用自定义函数示例。
我在 youtube 上看到有从令牌获取用户的选项,但没有功能
class UserAPI(generics.RetrieveAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
serializer_class = UserSerializer
def get_object(self):
return self.request.user
那么是否有一种乳清可以从自定义函数中的令牌中获取相应的用户
解决方案
太好了,我在几个小时内发现 knox 没有将完整的 token_key 存储在数据库中。
我们可以获得的真实令牌是这样的:
a512529e7ffceaa8406ceb616d088b3422ad15811a5eb470e8f4c4896c9aa649
在数据库中 token_key 默认存储a512529e
。8位数。
使用此过滤对象:
knox_object = AuthToken.objects.filter(token_key__startswith=token[:8]).first()
然后获取用户对象
knox_object.user.username
或者您可以更快地使用它
from knox.settings import CONSTANTS
knox_object = AuthToken.objects.filter(token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]).first()
来自 knox 源代码
class CONSTANTS:
'''
Constants cannot be changed at runtime
'''
TOKEN_KEY_LENGTH = 8
DIGEST_LENGTH = 128
SALT_LENGTH = 16
def __setattr__(self, *args, **kwargs):
raise Exception('''
Constant values must NEVER be changed at runtime, as they are
integral to the structure of database tables
''')
CONSTANTS = CONSTANTS()
可以看到TOKEN_KEY_LENGTH
是 8 位数字。
我写了一个简单的函数来做到这一点
from knox.models import AuthToken
from knox.settings import CONSTANTS
def get_user_from_token(token):
objs = AuthToken.objects.filter(token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH])
if len(objs) == 0:
return None
return objs.first().user
现在生活更轻松。:)
是的,我改进并发布了它。
你可以试试我的叉子。如果您只是想@smart_token_user
在任何 GET/POST/PUT/... 方法之前添加。
https://github.com/xros/django-rest-knox
只需 git clone,然后pip install ./
我写了一个装饰器。
有了这个,在我们的应用程序views.py中我们可以很容易地通过这样做来获取用户对象,@smart_token_user
将修改请求处理程序。request.user
只有在令牌有效时,我们才能拥有一个attr。所有无效的尝试都将被 HTTP 401 Unauthorized 响应丢弃。有了这个装饰器,生活可以更轻松。
from knox.models import smart_token_user
class CheckUserEmail(generics.RetrieveAPIView):
permission_classes = (IsAuthenticated,)
@smart_token_user
def get(self, request):
return Response({
"username": request.user.username,
"email": request.user.email,
"password": request.user.password,
}, status=status.HTTP_200_OK)
或者,如果您愿意,也可以像原来一样使用:authentication_classes = (TokenAuthentication,)
class CheckUserEmail(generics.RetrieveAPIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
def get(self, request):
return Response({
"username": request.user.username,
"email": request.user.email,
"password": request.user.password,
}, status=status.HTTP_200_OK)