在Django中,自定义User模型,使用token鉴权,实现注册、登录、修改密码等API

在Django中,自定义User模型,实现注册、登录、修改密码、登出、首页5个API。

大体步骤是:自定义User模型->重构鉴权后台->settings设置->views修改->Postman测试。

1、在models.py中,仿照Django官网提供的样例,自定义User模型,主要是增加了phone这个必选字段。

Django文档地址:https://docs.djangoproject.com/en/2.0/topics/auth/customizing/

代码如下:

from django.db import models
from django.contrib.auth.models import ( BaseUserManager, AbstractBaseUser)


class CustomUserManager(BaseUserManager):
    def create_user(self, user_id, phone, email=None, password=None):
        """
        Creates and saves a User with the given phone,....
        """
        if not phone:
            raise ValueError('phone must be given when create user')
        if email:
            email = self.normalize_email(email)

        user = self.model(
            user_id = user_id,
            phone = phone,
            email = email,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, user_id, phone=None, email=None, password=None):
        user = self.create_user(
            user_id,
            phone=phone,
            email=email,
            password=password,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class CustomUser(AbstractBaseUser):
    user_id = models.CharField(
        max_length=30,
        unique=True,
    )
    phone = models.CharField(
        max_length=30,
        null=True,
        blank=True,
        unique=True,
        default=None,
    )
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
        null=True,
        blank=True,
    )

    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = CustomUserManager()

    USERNAME_FIELD = 'user_id'
    REQUIRED_FIELDS = ['phone']

    def __str__(self):
        return self.user_id

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin   # 是admin的话,就是雇员

  

2、在app目录下,新建backends.py文件,仿照Django官网提供的样例(还是上面给出的网址),写出自定义的CustomBackend(自定义的鉴权后台):

from .models import CustomUser as User


class CustomBackend:

    def authenticate(self,
                     request,
                     user_id=None,
                     phone=None,
                     password=None,
                     **kwargs):
        # 支持后台登录功能,因为admin登录提交的时候会发送username字段
        if user_id is None:
            user_id = kwargs.get('username')

        try:
            if phone:
                user = User.objects.get(phone=phone)
            elif user_id:
                user = User.objects.get(user_id=user_id)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

3、在settings中设置:

(1)要使用自定义的User模型和鉴权后台:

# Custom User
AUTH_USER_MODEL = 'chat_user.CustomUser'
# Custom Authentication backend
AUTHENTICATION_BACKENDS = ['chat_user.backends.CustomBackend']

(2)确定使用token鉴权:

INSTALLED_APPS = [
    ......
    'rest_framework',
    'rest_framework.authtoken',
    'chat_user',
]

 4、修改views.py,实现注册、登录、修改密码、登出、首页5个API(前4个是post方式,最后一个是get方式):

import uuid
from django.shortcuts import render
from django.contrib import auth

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.authentication import BasicAuthentication,SessionAuthentication,TokenAuthentication
from rest_framework.authtoken.models import Token
from rest_framework.permissions import AllowAny,IsAuthenticated

from .models import CustomUser as User


class Register(APIView):
    def post(self, request):
        """
        注册
        """
        phone = request.data.get('phone')
        password = request.data.get('password')
        user_id = uuid.uuid4().hex
        user = User.objects.create_user(user_id=user_id, phone=phone, password=password)
        user.save()
        context = {
            "status": status.HTTP_200_OK,
            "msg": "用户注册成功"
        }
        return Response(context)


class Login(APIView):
    authentication_classes = (BasicAuthentication,TokenAuthentication)   # 使用基础的和token的验证方式
    permission_classes = (AllowAny,)    # 允许所有人访问

    def post(self, request):
        """
        登录
        """
        phone = request.data.get('phone')
        password = request.data.get('password')
        user = auth.authenticate(request, phone=phone, password=password)
        if user:
            auth.login(request, user)
            token = Token.objects.create(user=user)
            context = {
                "status": status.HTTP_200_OK,
                "msg": "用户登录成功",
                "user_id":request.user.user_id,
                "token":token.key,
            }
        else:
            context = {
                "status": status.HTTP_403_FORBIDDEN,
                "msg": "用户名或密码错误",
            }
        return Response(context)


class Logout(APIView):
    authentication_classes = (BasicAuthentication,TokenAuthentication)
    permission_classes = (IsAuthenticated,)

    def post(self, request):
        """
        登出
        """
        #auth.logout(request)
        Token.objects.filter(user=request.user).delete()
        context = {
            "status": status.HTTP_200_OK,
            "msg": "退出成功"
        }
        return Response(context)


class Password(APIView):
    authentication_classes = (BasicAuthentication,TokenAuthentication)   # 使用基础的和token的验证方式
    permission_classes = (IsAuthenticated,)     # 只允许所有通过鉴权的人访问

    def post(self, request):
        """
        修改密码
        """
        new_password1 = request.data.get('new_password1')
        new_password2 = request.data.get('new_password2')
        if new_password1 and new_password1 == new_password2:
            request.user.set_password(new_password1)
            request.user.save()
            context = {
                "status": status.HTTP_200_OK,
                "msg": "修改密码成功"
            }
        else:
            context = {
                "status": status.HTTP_403_FORBIDDEN,
                "msg": "两次密码不一样或没密码"
            }
        return Response(context)


class Index(APIView):
    authentication_classes = (BasicAuthentication,TokenAuthentication)      # 使用基础的和token的验证方式
    permission_classes = (IsAuthenticated,)     # 只允许所有通过鉴权的人访问

    def get(self,request):
        context = {
            "data":"Hello World!",
            "status":200,
            "msg":"访问index成功"
        }
        return Response(context)

5、确认urls已配置好,包括项目的urls和应用的urls,下面列出的仅是应用的urls:

from django.urls import path, include, re_path
from . import views


urlpatterns = [
    path('register/', views.Register.as_view()),
    path('login/', views.Login.as_view()),
    path('logout/', views.Logout.as_view()),
    path('password/', views.Password.as_view()),
    path('index/', views.Index.as_view()),
]

6、写入数据库:

python manage.py makemigrations

python manage.py migrate

在写入的时候可能会报错,django.db.utils.IntegrityError: UNIQUE constraint failed,是因为之前数据库中有user的数据,而表结构不一样,删除原来的用户数据再写入就行;我是删除了整个sqlite数据库,重新写入数据库。

7、开启服务(python manage.py runserver),用Postman测试各个接口,成功。

原文地址:https://www.cnblogs.com/djlbolgs/p/12758886.html