在 Django (DRF) 中使用外部 API 进行基于令牌的身份验证
Using external API for token based authentication in Django (DRF)
上下文
我的 API 接受我可以传递给外部端点的 jwt 令牌,如果 invalid/expired 或用户信息仍然有效,它将 return 401。基于此,我将 return 401 或属于用户的过滤数据。此外,POST 请求需要涉及写入此资源属于谁才能使 GET 工作。我试图通过覆盖 get_queryset 和 perform_create 方法来做到这一点。
我的视图集看起来像这样:
class ReportViewSet(AuthorizedUserBasedFilteredViewset):
queryset = Report.objects.all()
serializer_class = ReportSerializer
def perform_create(self, serializer):
try:
username = self.get_authorized_user()['user']['username']
except Exception as e:
return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
serializer.save(creatd_by=username)
def get_queryset(self):
try:
username = self.get_authorized_user()['user']['username']
except Exception as e:
return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
return Report.objects.filter(created_by=username)
这不起作用,因为 get_queryset 需要一个查询集作为响应。
问题
- 如何冒泡 get_queryset 中的授权异常?我应该完全覆盖身份验证的其他方法吗?我仍然需要将收到的用户名传递给 get_queryset 才能使身份验证成功
- 有更好的方法吗?我觉得调用外部身份验证 API 并将用户设置为可通过 get_queryset 和 perform_create 方法访问将理想地放在代码中的其他地方。我查看了 RemoteUserAuthenticationBackend,但仍然涉及创建用户对象,但对于此用例,用户模型完全是外部的
而不是
return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
使用这个
raise NotAuthenticated(detail='Token does not exist')
希望上面的行已经解决了您的第一个问题。
第二个问题。
您可以扩展 TokenAuthentication
然后实现 def authenticate_credentials(self, key):
方法。 每次调用外部API来获取用户不是一个好主意。相反,您应该从外部源获取一次 JTW 令牌,然后在 header 中传递 JWT 令牌,就像每个 API 调用的 Authorization : Bearer cn389ncoiwuencr
一样。然后你应该在当前系统中解码 JWT 令牌。
from rest_framework.authentication import TokenAuthentication
from django.contrib.auth import get_user_model
class CustomTokenAuthentication(TokenAuthentication):
keyword = 'Bearer' # token type
def authenticate_credentials(self, key):
#decode JWT.
username = get_username()
User = get_user_model()
user = User(username=username)
return user, key
最后,将此 class 添加到 settings.py 文件。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'path.of.CustomTokenAuthentication',
)
}
这将适用于您的所有观点。或者您可以申请查看特定授权 class.
class Sample(ViewSet):
authentication_classes = (CustomTokenAuthentication,)
从现在开始,您可以通过 request.user
在视图或视图集中访问用户。就是这样。
上下文
我的 API 接受我可以传递给外部端点的 jwt 令牌,如果 invalid/expired 或用户信息仍然有效,它将 return 401。基于此,我将 return 401 或属于用户的过滤数据。此外,POST 请求需要涉及写入此资源属于谁才能使 GET 工作。我试图通过覆盖 get_queryset 和 perform_create 方法来做到这一点。
我的视图集看起来像这样:
class ReportViewSet(AuthorizedUserBasedFilteredViewset):
queryset = Report.objects.all()
serializer_class = ReportSerializer
def perform_create(self, serializer):
try:
username = self.get_authorized_user()['user']['username']
except Exception as e:
return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
serializer.save(creatd_by=username)
def get_queryset(self):
try:
username = self.get_authorized_user()['user']['username']
except Exception as e:
return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
return Report.objects.filter(created_by=username)
这不起作用,因为 get_queryset 需要一个查询集作为响应。
问题
- 如何冒泡 get_queryset 中的授权异常?我应该完全覆盖身份验证的其他方法吗?我仍然需要将收到的用户名传递给 get_queryset 才能使身份验证成功
- 有更好的方法吗?我觉得调用外部身份验证 API 并将用户设置为可通过 get_queryset 和 perform_create 方法访问将理想地放在代码中的其他地方。我查看了 RemoteUserAuthenticationBackend,但仍然涉及创建用户对象,但对于此用例,用户模型完全是外部的
而不是
return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)
使用这个
raise NotAuthenticated(detail='Token does not exist')
希望上面的行已经解决了您的第一个问题。
第二个问题。
您可以扩展 TokenAuthentication
然后实现 def authenticate_credentials(self, key):
方法。 每次调用外部API来获取用户不是一个好主意。相反,您应该从外部源获取一次 JTW 令牌,然后在 header 中传递 JWT 令牌,就像每个 API 调用的 Authorization : Bearer cn389ncoiwuencr
一样。然后你应该在当前系统中解码 JWT 令牌。
from rest_framework.authentication import TokenAuthentication
from django.contrib.auth import get_user_model
class CustomTokenAuthentication(TokenAuthentication):
keyword = 'Bearer' # token type
def authenticate_credentials(self, key):
#decode JWT.
username = get_username()
User = get_user_model()
user = User(username=username)
return user, key
最后,将此 class 添加到 settings.py 文件。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'path.of.CustomTokenAuthentication',
)
}
这将适用于您的所有观点。或者您可以申请查看特定授权 class.
class Sample(ViewSet):
authentication_classes = (CustomTokenAuthentication,)
从现在开始,您可以通过 request.user
在视图或视图集中访问用户。就是这样。