Django Rest Framework 中的 JWT 身份验证错误“无效签名”

Posted

技术标签:

【中文标题】Django Rest Framework 中的 JWT 身份验证错误“无效签名”【英文标题】:JWT Authentication Error "Invalid Signature" in Django Rest Framework 【发布时间】:2018-03-28 06:15:29 【问题描述】:

我是 Python 和 Django REST 框架的新手,我正在尝试使用 JWT (https://jpadilla.github.io/django-rest-framework-jwt/) 配置身份验证。我可以在注册时为用户创建一个令牌,但是当我尝试通过我的 api 进行身份验证时出现“无效签名”错误。我已经在https://jwt.io/ 确认了错误。这似乎意味着我的令牌创建不正确。有什么想法吗?

这是我的配置:

from django.db import models

class User(models.Model):
    first_name = models.CharField(max_length=45)
    last_name = models.CharField(max_length=45)
    username = models.CharField(max_length=45, unique=True)
    phone = models.CharField(max_length=20)
    password = models.CharField(max_length=100, blank=False, default='')

from rest_framework import serializers
from . models import User
from django.contrib.auth.hashers import make_password

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'username', 'phone', 
'password')
    extra_kwargs = 'password': 'write_only': True
    def create(self, validated_data):
        # the create method creates and saves an object in a single statement
        user = User.objects.create(
            first_name = validated_data['first_name'],
            last_name = validated_data['last_name'],
            username = validated_data['username'],
            phone = validated_data['phone'],
            password = make_password(validated_data['password']),
        )

        return user

from joyrides_api.models import User
from joyrides_api.serializers import UserSerializer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from rest_framework_jwt.utils import jwt_payload_handler
from rest_framework import permissions
from rest_framework_jwt.settings import api_settings
from rest_framework.permissions import AllowAny
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

class UserList(APIView):

    permission_classes = (AllowAny,)
    # this method creates the user
    def post(self, request, format=None):
            serializer = UserSerializer(data=request.data)
            if serializer.is_valid():
                # the save method calls serializer's create method
                user = serializer.save()
                if user:
                    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
                    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                    payload = jwt_payload_handler(user)
                    token = jwt_encode_handler(payload)
                    json = serializer.data
                    json['token'] = token
                    return Response(json, status=status.HTTP_201_CREATED)

            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

【问题讨论】:

【参考方案1】:

您还需要指定authentication_classes。 让它为空,它应该可以工作。

【讨论】:

我确实在我的身份验证路由上设置了 JWT 身份验证类,因为我相信这是它们的实用程序。我确实尝试在我的创建令牌路由上设置它,但仍然收到无效签名。 如果我理解正确,您成功地从这个UserList 视图获取令牌,但不能在其他视图上使用该令牌(获取“无效签名”)? 我可以从视图中获取令牌,但签名无效。我使用jwt.io 的验证器仔细检查了令牌(您可以在首页粘贴编码令牌并输出内容)。标头和有效负载正确,但签名无效。 好的,我用自己的 JWT 令牌检查了这一点。它确实说无效签名。但它可以与api一起使用。我认为“无效签名”背后的原因是我们将JWT_PUBLIC_KEYJWT_PRIVATE_KEY 设置为无。如果我们按照cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeycryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey声明密钥,我们就可以得到签名验证。 是的。我只是能够使用 createsuperuser 方法成功地对用户进行身份验证。这与我的用户模型如何与 jwt 框架交互有关。【参考方案2】:

我的问题是当我使用 django.db.model 创建方法创建用户时:

from . models import User

def create(self, validated_data):
        user = User.objects.create(
            first_name = validated_data['first_name'],
            ...
        )

        return user

我还没有在 django.contrib.auth.models 的 Django 用户模型中创建用户,这是 Django 和 JWT 框架用于身份验证的模型。对于初学者来说,这并不是那么简单,考虑到 JWT 与 Django 的流行(或者看起来如此),我有点惊讶这不是一个更大的问题。我想有人会告诉我我应该花更多的时间在文档上。

我离题了,优雅的解决方法是通过扩展 django.contribut.auth.models 的 AbstractUser 来自定义您的用户模型,(我相信)它将您的用户模型的相关部分链接到 Django 的模型。此处说明:https://docs.djangoproject.com/en/1.11/topics/auth/customizing/

我为启动并运行它所做的选择(尽管我计划很快切换到自定义模型)是使用 django.contrib.auth.models 的 create_user 方法将您的用户对象保存到 Django 用户模型,该方法操作相同到上面的 create 方法,除了它保存到 Django 的用户模型。

【讨论】:

【参考方案3】:

我发现创建自定义用户模型时出现“无效签名”错误。我通过以下方式解决了这个问题:

    基于 Django 的用户模型实例化模型:

``

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    .....

``

    在 settings.py 中,使用 AUTH_USER_MODEL 指向自定义用户模型。

``

AUTH_USER_MODEL = 'user.User'

``

“user.User”指向用户应用中的用户模型。

继续生成令牌。令牌将立即生效。

【讨论】:

以上是关于Django Rest Framework 中的 JWT 身份验证错误“无效签名”的主要内容,如果未能解决你的问题,请参考以下文章

Django-Rest-Framework 中的序列化程序问题

如何从 django-rest-framework 中的文件列表中过滤图像

Django Rest Framework 中的 JWT 身份验证错误“无效签名”

Django REST framework视图

django框架学习六:优化views.py文件,使用rest_framework中的APIVew和Response返回

Django REST Framework 中的外键值