[英]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"}
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.