简体   繁体   English

在 Django (DRF) 中使用外部 API 进行基于令牌的身份验证

[英]Using external API for token based authentication in Django (DRF)

Context语境

My API accepts a jwt-token that I can pass to an external endpoint which will return 401 if invalid/expired or user information if still valid.我的 API 接受一个 jwt 令牌,我可以将其传递给外部端点,如果无效/过期,则返回 401,如果仍然有效,则返回用户信息。 Based on this I will either return 401 or filtered data belonging to the user.基于此,我将返回 401 或属于用户的过滤数据。 Also, POST request's need to involve writing who this resource belongs to for the GET to work.此外,POST 请求需要涉及写入此资源属于谁以使 GET 工作。 I tried to do this by overriding the get_queryset and perform_create methods.我试图通过覆盖 get_queryset 和 perform_create 方法来做到这一点。

My viewset looks something like this:我的视图集看起来像这样:

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)

This doesn't work because get_queryset expects a queryset as response.这不起作用,因为 get_queryset 需要一个查询集作为响应。

Questions问题

  1. How do I bubble up the authorize exception in get_queryset?如何在 get_queryset 中冒泡授权异常? Is there some other method I should be overriding to the authentication entirely?是否有其他一些方法我应该完全覆盖身份验证? I still need to pass the username recieved to get_queryset for the authentication to be successful我仍然需要将收到的用户名传递给 get_queryset 才能使身份验证成功
  2. Is there a better way to do this?有一个更好的方法吗? I feel that the call to the external authentication API and setting the user to be accessible by the get_queryset and perform_create methods would ideally go somewhere else in the code.我觉得调用外部身份验证 API 并将用户设置为可通过 get_queryset 和 perform_create 方法访问理想情况下会放在代码中的其他地方。 I looked at the RemoteUserAuthenticationBackend but that still involved creation of a User object but for this use case the user model is entirely external我查看了 RemoteUserAuthenticationBackend 但这仍然涉及创建 User 对象,但对于这个用例,用户模型完全是外部的

Instead of代替

return Response({'error': 'Token does not exist'}, status=HTTP_401_UNAUTHORIZED)

use this用这个

raise NotAuthenticated(detail='Token does not exist')

Hope above line has addressed your 1st question.希望以上行已经解决了您的第一个问题。

For 2nd question.对于第二个问题。 You can extend TokenAuthentication and then implement def authenticate_credentials(self, key): method.您可以扩展TokenAuthentication ,然后实现def authenticate_credentials(self, key):方法。 It is not a good idea to call external API to fetch user each time .每次都调用外部 API 来获取用户不是一个好主意 Rather you should get JTW token one time from external source then pass JWT token in header like Authorization : Bearer cn389ncoiwuencr for each API call.相反,您应该从外部源获取一次 JTW 令牌,然后在像Authorization : Bearer cn389ncoiwuencr这样的标头中为每个 API 调用传递 JWT 令牌。 Then you should decode JWT token in current system.然后你应该在当前系统中解码 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

Finally, add this class at settings.py file.最后,在 settings.py 文件中添加这个类。

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'path.of.CustomTokenAuthentication',
    )
}

That will apply to all of your views.这将适用于您的所有观点。 or you can apply view specific auth class.或者您可以应用查看特定的身份验证类。

class Sample(ViewSet):
    authentication_classes = (CustomTokenAuthentication,)

From now you can access user by request.user at views or viewset.从现在开始,您可以通过request.user在视图或视图集访问用户。 That's it.就是这样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM