DJANGO + JWT 令牌认证

Posted

技术标签:

【中文标题】DJANGO + JWT 令牌认证【英文标题】:DJANGO + JWT TOKEN AUTHENTICATION 【发布时间】:2020-10-24 09:46:12 【问题描述】:

所以我试图为我的 android 应用程序构建一个后端。我正在尝试应用与 JWT 令牌一起使用的登录过程

这就是我所做的:

    我已经制作了一个自定义用户模型。 自定义我的超级用户以获取电话号码和密码,而不是用户名和密码 我已成功创建超级用户并将其存储在我的数据库中(使用 postgreSQL)。 我还自定义了我的令牌声明和响应,如我的 LoginSerializer 类的 serializers.py 中所示。

但是,我做了之后遇到了一些问题:

    现在,在自定义用户模型后,我无法使用新的自定义用户模型登录到 Django 管理,即使我已成功创建超级用户。 即使使用刚刚创建的成功超级用户帐户对令牌声明进行了自定义,我仍然无法获取令牌。

以下是一些错误信息:

以下是一些附件:

models.py

from django.db import models   
from django.contrib.auth.models import AbstractBaseUser,BaseUserManager
from django.utils.translation import ugettext_lazy as _
from phone_field import PhoneField

class RegisterUserManager(BaseUserManager):

    def create_user(self, phone_number,password):

        if not phone_number:
            raise ValueError('The phone number must be set')

        user = self.model(
            phone_number=phone_number,
            password = password,)

        user.save(using = self._db)
       
        return user
        
    def create_superuser(self,phone_number,password, **extra_fields):

        user = self.create_user(
            phone_number,
            password = password
        )

        user.is_admin =  True
        user.save(using= self._db)

        return user


class RegisterUser(AbstractBaseUser):
    first_name = models.CharField(name = 'first_name',max_length=255,default = '')
    last_name = models.CharField(name='last_name', max_length=255,default = '')
    email = models.EmailField(name='email', max_length = 255)
    phone_number = PhoneField(name='phone_number',unique=True)
    birthday = models.DateField(name ='birthday',null= True)
    nickname = models.CharField(max_length=100,name = 'nickname')
    is_active = models.BooleanField(default = True)
    is_admin = models.BooleanField(default= False)
    last_login = models.DateTimeField(auto_now= True)

    USERNAME_FIELD = 'phone_number'
    REQUIRED_FIELDS = []

    objects = RegisterUserManager()

    def __str__(self):
        return self.phone_number

    def has_perm(self, perm, obj = None):
        return True

    def has_module_perms(self,perm,obj = None):
        return True

    @property
    def is_staff(self):
        return self.is_admin

views.py

from django.shortcuts import render
from django.http import HttpResponse,JsonResponse   
from rest_framework.parsers import JSONParser
from restaccount.models import RegisterUser
# Login
from restaccount.serializers import RegisterSerializers,LoginSerializer
# LoginSerializers
from django.views.decorators.csrf import csrf_exempt
from rest_framework.generics import CreateAPIView

from rest_framework_simplejwt.views import TokenObtainPairView

from rest_framework.permissions import (AllowAny,IsAuthenticated)
# from rest_framework.generics import CreateAPIView

class RegisterView(CreateAPIView):
    permission_classes = (AllowAny,)
    serializer_class = RegisterSerializers
    queryset = RegisterUser.objects.all()

class LoginView(TokenObtainPairView):
    serializer_class = LoginSerializer

serializers.py

from rest_framework.serializers import (ModelSerializer,ValidationError)
from restaccount.models import RegisterUser
# Login

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

from rest_framework import serializers

class RegisterSerializers(ModelSerializer):
    class Meta:
        model = RegisterUser
        fields =['id',
                'first_name',
                'last_name',
                'email',
                'password',
                'phone_number',
                'nickname',
                'birthday',
                ]

    def create(self,validated_data):
        first_name = validated_data['first_name']
        last_name = validated_data['last_name']
        email = validated_data['email']
        password = validated_data['password']
        phone_number = validated_data['phone_number']
        nickname = validated_data['nickname']
        birthday = validated_data['birthday']
        user_obj = RegisterUser(
            first_name = first_name,
            last_name = last_name,
            email = email,
            password = password,
            phone_number = phone_number,
            nickname = nickname,
            birthday = birthday,
        )
        user_obj.save()
        return user_obj

    def update(self, instance,validated_data):
        instance.first_name = validated_data.get('first_name',instance.first_name)
        instance.last_name = validated_data.get('last_name', instance.last_name)
        instance.email = validated_data.get('email', instance.email)
        instance.password = validated_data.get('password', instance.password)
        instance.phone_number = validated_data.get('phone_number', instance.phone_number)
        instance.nickname = validated_data.get('nickname', instance.nicknames)
        instance.birthday = validated_data.get('birthday',instance.birthday)
        instance.save()
        return instance

    def validate(self,data):
        return data
    
    def validate_phone_number(self,value):
        phone_number = value
        user_qs = RegisterUser.objects.filter(phone_number = phone_number)
        if user_qs.exists():
            raise ValidationError("This phone number is registered")
        return value


class LoginSerializer(TokenObtainPairSerializer):

    @classmethod
    def get_token(cls,user):
        token = super().get_token(user)

        token['phone_number'] = user.phone_number
        token['password'] = user.password

        return token

    def validate(self,attrs):
        data = super().validate(attrs)

        refresh = self.get_token(self.user)
        data['refresh'] = str(refresh)
        data['access'] = str(refresh.access_token)

        data['phone_number'] = self.user.phone_number

        return data

【问题讨论】:

【参考方案1】:

事实证明,模型中的密码字段必须经过哈希处理,使得 user.set_password(密码)。如果您想从 API 端点创建用户,这也是同样的情况。您必须将哈希密码存储在您的数据库中。

但是,我不知道为什么会这样。

【讨论】:

将密码保存为纯文本是一个严重的安全问题。如果您的数据库受到威胁,则可以假定用户帐户是安全的,因为散列密码是不可逆的。永远不要将密码保存为纯文本。

以上是关于DJANGO + JWT 令牌认证的主要内容,如果未能解决你的问题,请参考以下文章

ANDROID VOLLEY + JWT TOKEN 认证 + DJANGO REST 框架

什么是JWT令牌认证?

Django rest 框架 jwt 令牌权限

使用 jwt 令牌认证识别用户

JWT 令牌是如何认证的?

真正的 Jwt 令牌认证