【问题标题】:Problem with JWT authentication in django-rest-frameworkdjango-rest-framework 中的 JWT 身份验证问题
【发布时间】:2019-07-29 17:13:43
【问题描述】:

我在使用 django-rest-knox 进行 JWT 身份验证时遇到问题。

错误是: Detail: Authentication credentials were not provided.

端点: /api/auth/login/

发往端点的 POST 请求中的标头: { Content-Type: application/json }

正文:

{
    "username": "admin",
    "password": 1234
}

登录 API 视图:

class UserLoginAPIView(generics.GenericAPIView):
    serializer_class = UserLoginSerializer

    def post(self, request, *args, **kwargs):
        data = request.data
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data
        token = AuthToken.objects.create(user)
        return Response({
            "user": UserSerializer(user,
                                   context=self.get_serializer_context()).data,
            "token": token
        })

序列化器:

class UserLoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()


    def validate(self, data):
        user = authenticate(**data)
        if user and user.is_active:
            return user
        raise serializers.ValidationError("Invalid Credentials")

默认设置:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'knox.auth.TokenAuthentication',
    ]
}

【问题讨论】:

标签: python django api django-rest-framework


【解决方案1】:

您好,您使用的 knox 似乎不完全相同,但本质上是相似的。您的视图似乎受到保护,可能是因为您的 DEFAULT_PERMISSION_CLASSES 设置。

如果您能够通过此视图登录,您必须设置

permission_classes = [AllowAny, ]

在你看来。

但是我不会那样做,因为这是一个 hack。 (我知道我经历过,我们把同一篇文章加红了)。

正确的做法是在 Django Configuration/Settings 文件中定义 User 序列化程序,以便在登录时检索到所需的信息。

REST_KNOX = {
    'USER_SERIALIZER': 'auth.serializers.UserRetrieveSerializer'
}

然后只需扩展默认登录视图并使用basic auth 作为身份验证类。

from knox.views import LoginView as KnoxLoginView
from rest_framework.authentication import BasicAuthentication
from rest_framework.permissions import IsAuthenticated

class LoginAPI(KnoxLoginView):
    """
    Login endpoint.
    """
    authentication_classes = [BasicAuthentication, ]
    permission_classes = [IsAuthenticated, ]

对于所有其他视图,您可以使用knox.auth.TokenAuthentication。 就是这样……

测试的相关代码是:

import base64

def get_basic_auth_header(username, password):
    return 'Basic %s' % base64.b64encode(
        ('%s:%s' % (username, password)).encode('ascii')).decode()

 from rest_framework.test import APITestCase

 class MyTestCase(APITestCase):
     username = 'foo'
     password = 'bar'

     def test_login(self):
         # Add basic auth credentials
         self.client.credentials(
             HTTP_AUTHORIZATION=get_basic_auth_header(
                 self.username, self.password))
         etc...

在你的urls.py

from knox import views as knox_views
from .views import LoginAPI

...
    url(r'^login/$', LoginAPI.as_view(), name='knox_login'),                    
    url(r'^logout/$', knox_views.LogoutView.as_view(), name='knox_logout'),     
    url(r'^logoutall/$', knox_views.LogoutAllView.as_view(), name='knox_logoutall'),
...


【讨论】:

  • 谢谢。我添加了 permission_classes = [AllowAny, ] 但没有任何改变。我以前测试过。
  • 是的,您实际上需要两者,扩展 KnoxLoginView 并添加 AllowAny。
  • 你能详细说明一下吗?您是否在 urls.py 文件中注册了您的视图?你需要一个代码 sn-p 用于 javascript 中的基本身份验证吗?
【解决方案2】:

我认为你的程序是错误的。根据 Knox 文档,您需要授予访问权限登录端点。但是您没有授予访问登录端点的权限。 所以你的登录端点看起来像这样,

# views.py 
from django.contrib.auth import login
from rest_framework import permissions
from rest_framework.authtoken.serializers import AuthTokenSerializer
from knox.views import LoginView as KnoxLoginView

class LoginView(KnoxLoginView):
    permission_classes = (permissions.AllowAny,)

    def post(self, request, format=None):
        serializer = AuthTokenSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)
        return super(LoginView, self).post(request, format=None)

# settings.py 
REST_KNOX = {
  'USER_SERIALIZER': 'knox.serializers.UserSerializer',
}

如果您在设置中使用用户序列化程序,您将获得带有请求用户用户名的令牌,如下所示

{"user":{"username":"admin"},"token":"00bd2a5e517800b75a8f36bbf3baea4c839169108b25a5a5ea599a4ecda974c0"}

更多细节在这里。 Knox

【讨论】:

    【解决方案3】:

    您从哪里得到错误“未提供凭据”?如果是在浏览器中手动调用路由的情况下,我认为没问题(至少我明白了,而数据在我的表中正确加载等)

    我遇到的问题是使用 knox 令牌进行身份验证在 Safari 和 iPad 上不起作用。原因是我的路线中有一个斜杠,这导致 301 - Moved 永久响应以及后续重定向,这显然没有转发令牌。我删除了尾部的斜杠,然后一切都很好。

    顺便说一句:使用

    permission_classes = (permissions.AllowAny,)
    

    似乎不对,我认为这或多或少与令牌的使用相矛盾。应该是

    permission_classes = [permissions.IsAuthenticated]
    

    【讨论】:

      【解决方案4】:

      如果您要深入使用 Apache,则将 WSGIPassAuthorization On 添加到 000-default.conf 文件中。这解决了我的问题。见:https://www.django-rest-framework.org/api-guide/authentication/

      【讨论】:

        猜你喜欢
        • 2019-01-01
        • 2020-04-10
        • 2015-06-01
        • 2017-12-23
        • 2019-11-20
        • 2021-04-04
        • 2021-05-22
        • 2018-02-25
        • 2019-02-19
        相关资源
        最近更新 更多