简体   繁体   English

django-rest-framework 中 JWT 身份验证的问题

[英]Problem with JWT authentication in django-rest-framework

I have a problem with JWT authentication using django-rest-knox.我在使用 django-rest-knox 进行 JWT 身份验证时遇到问题。

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

ENDPOINT: /api/auth/login/端点: /api/auth/login/

Headers in the POST request to the endpoint: { Content-Type: application/json }发送到端点的 POST 请求中的标头: { Content-Type: application/json }

body:身体:

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

Login API View:登录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
        })

Serializer:序列化器:

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")

Default Settings:默认设置:

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

I think your procedure is wrong.我认为你的程序是错误的。 According to Knox documents, You need to give an access permission login endpoint.根据 Knox 文档,您需要授予访问权限登录端点。 But you did not give permission to access your login endpoint.但是您没有授予访问登录端点的权限。 So your login endpoint looks like this,所以你的登录端点看起来像这样,

# 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',
}

If you use the user serializer in your setting you get token with the username of the requesting user like bellow如果您在设置中使用用户序列化程序,您将获得带有请求用户的用户名的令牌,如下所示

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

More details here.更多细节在这里。 Knox 诺克斯

Hi it seems that you are using knox which is not exactly the same, but in essence it is similar.您好,您使用的 Knox 似乎并不完全相同,但本质上是相似的。 Your view seems protected probably because of your DEFAULT_PERMISSION_CLASSES settings.您的视图似乎受到保护,可能是因为您的DEFAULT_PERMISSION_CLASSES设置。

If you to be able to login via this view you'd have to set如果您能够通过此视图登录,则必须设置

permission_classes = [AllowAny, ]

on your view.在你看来。

However I would not do that since this is a hack.但是我不会这样做,因为这是一个黑客。 (I know I have been through it and we red the same article). (我知道我经历过它,我们红了同一篇文章)。

The correct way to do it is to define the User serializer in the Django Configuration/Settings file, so that you can retrieve the info you want when you log in.正确的做法是在 Django Configuration/Settings 文件中定义 User 序列化程序,这样你就可以在登录时检索你想要的信息。

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

Then simply extend the default login view and use basic auth as authentication class.然后简单地扩展默认登录视图并使用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, ]

And for all the other views you could use knox.auth.TokenAuthentication .对于所有其他视图,您可以使用knox.auth.TokenAuthentication And that's it...就是这样......

Relevant code for testing it is:测试它的相关代码是:

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...

In your urls.py在你的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'),
...


Where do you get your error "credentials were not provided"?您在哪里收到错误“未提供凭据”? If it is the case when calling the route by hand in the browser, I think it is fine (at least I get it, while data is loaded properly in my tables etc.)如果在浏览器中手动调用路由时出现这种情况,我认为这很好(至少我明白了,而数据已正确加载到我的表中等)

I had the problem that authentication with knox token did not work on Safari and on iPad.我遇到的问题是,使用 Knox 令牌进行身份验证在 Safari 和 iPad 上不起作用。 The reason was that I had a trailing slash in my routes and this caused 301 - Moved permanently responses with subsequent redirects, which obviously did not forward the token.原因是我的路由中有一个尾部斜杠,这导致 301 - Moved 永久响应与后续重定向,这显然没有转发令牌。 I removed the trailing slashes and everything was fine then.我删除了尾部斜杠,然后一切都很好。

By the way: Using顺便说一句:使用

permission_classes = (permissions.AllowAny,)

does not seem to be right, I think it more or less contradicts the use of tokens.似乎不对,我认为它或多或少地与令牌的使用相矛盾。 It should be它应该是

permission_classes = [permissions.IsAuthenticated]

If you are deeploying to the Apache then add the WSGIPassAuthorization On to the 000-default.conf file.如果您正在深入使用 Apache,则将 WSGIPassAuthorization On 添加到 000-default.conf 文件中。 That solved my issues.那解决了我的问题。 See:https://www.django-rest-framework.org/api-guide/authentication/请参阅:https ://www.django-rest-framework.org/api-guide/authentication/

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

相关问题 Django-Rest-Framework JWT单元测试说“未提供身份验证” - Django-Rest-Framework JWT Unit Test Saying “No Authentication Provided” Django Rest框架中的JWT身份验证 - JWT authentication in django rest framework 带有Django OAuth 2.0的Django-rest-framework给出了身份验证错误 - Django-rest-framework with django OAuth 2.0 giving authentication error 使用 Djoser、django-rest-framework-jwt 和 django-rest-framework 注册后获取 Token - Get Token after Registration with Djoser, django-rest-framework-jwt and django-rest-framework Django-rest-framework 教程 4:身份验证期间的 AttributeError - AttributeError during Django-rest-framework tutorial 4: authentication "在 django-rest-framework 中,是否可以同时使用 oauth 和 session 身份验证?" - In django-rest-framework, is it possible to use oauth and session authentication simultaneously? 更改 django-rest-framework 中的默认认证消息 - Changing the default authentication message in django-rest-framework Django Rest Framework 自定义 JWT 认证 - Django Rest Framework Custom JWT authentication JWT 和 Django Rest 框架中的自定义身份验证 - JWT and custom authentication in Django Rest Framework Django-rest-framework {“详细信息”:“未提供身份验证凭据。” } 使用 django-rest-knox - Django-rest-framework {“detail”: “Authentication credentials were not provided.” } using django-rest-knox
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM