【问题标题】:Using external API for token based authentication in Django (DRF)在 Django (DRF) 中使用外部 API 进行基于令牌的身份验证
【发布时间】:2020-06-23 16:02:48
【问题描述】:

上下文

我的 API 接受一个 jwt-token,我可以将其传递给外部端点,如果无效/过期,它将返回 401,如果仍然有效,则返回用户信息。基于此,我将返回 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 需要一个查询集作为响应。

问题

  1. 如何在 get_queryset 中冒泡授权异常?是否有其他方法我应该完全覆盖身份验证?我仍然需要将收到的用户名传递给 get_queryset 才能成功进行身份验证
  2. 有没有更好的方法来做到这一点?我觉得调用外部身份验证 API 并将用户设置为可由 get_queryset 和 perform_create 方法访问,理想情况下会转到代码中的其他位置。我查看了 RemoteUserAuthenticationBackend,但仍然涉及创建用户对象,但对于这个用例,用户模型完全是外部的

【问题讨论】:

    标签: django authentication django-rest-framework jwt django-authentication


    【解决方案1】:

    代替

    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 令牌,然后在每个 API 调用的标头中传递 JWT 令牌,如 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
    

    最后,在 settings.py 文件中添加这个类。

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

    这将适用于您的所有观点。或者您可以应用视图特定的身份验证类。

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

    从现在开始,您可以在视图或视图集中通过request.user 访问用户。而已。

    【讨论】:

    • 我已经编辑了我的问题以详细说明我的第二个问题,但这绝对适用于第一个问题:)
    • @ujjwal-gupta,请提及get_authorized_user()dict 的定义或正文。同样在Report 模型中,什么字段类型是created_by。也就是说username的类型
    • get_authorized_user() 只是从授权 API 的 json 响应中返回一个字典。用户名是我在报告模型中设置为 created_by 的字符串
    • 现在看看
    猜你喜欢
    • 2015-10-14
    • 2017-06-05
    • 1970-01-01
    • 2021-09-05
    • 2016-01-23
    • 2011-06-28
    • 2016-08-24
    • 1970-01-01
    • 2015-10-07
    相关资源
    最近更新 更多