【补充】用户多方式登陆

发布时间 2023-08-01 12:09:34作者: Chimengmeng

【补充】用户多方式登陆

【模型表】

from django.db import models

# Create your models here.
from django.contrib.auth.models import AbstractUser


class UserInfo(AbstractUser):

    phone = models.CharField(max_length=32)

【序列化类】

# -*-coding: Utf-8 -*-
# @File : user_serializer .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/1
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from rest_framework.exceptions import ValidationError
from app01.models import UserInfo
import re

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class UserSerializer(serializers.ModelSerializer):
    username = serializers.CharField(max_length=32)

    class Meta:
        model = UserInfo
        # 继承 ModelSerializer 后,字段是映射过来的
        # 但是username字段是唯一的
        # 反序列化校验的时候,字段自己的规则,会去数据库查询有没有和这个用户,如果有则报错
        # 解决方式:重写 username 字段
        fields = ["username", "password"]  # 只做反序列化的校验

    def validate(self, attrs):
        # attrs : 前端传入的校验过的数据,字段自己的局部钩子
        # (1)获取前端传入的数据
        username = attrs.get('username')  # 拿到的参数可能是手机号/邮箱/用户名
        password = attrs.get('password')
        # (2)校验用户是否存在
        # (2.1)先查找用户
        if re.match(r'^1(3[0-9]|5[0-3,5-9]|7[1-3,5-8]|8[0-9])\d{8}$', username):
            user = UserInfo.objects.filter(phone=username).first()
        elif re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$', username):
            user = UserInfo.objects.filter(email=username).first()
        else:
            user = UserInfo.objects.filter(username=username).first()

        # 校验密码
        if user and user.check_password(password):
            # (3)签发token
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            self.user = user
            self.token = token
            return attrs
        else:
            raise ValidationError("用户名或密码错误")

【视图】

from django.shortcuts import render

# Create your views here.
from rest_framework.viewsets import ViewSet
from app01 import models
from app01.serializers.user_serializer import UserSerializer
from rest_framework.response import Response


class UserView(ViewSet):
    back_dict = {"code": 200, "msg": ""}

    def login(self, request):
        # (1)得到序列化类
        user_ser = UserSerializer(data=request.data)
        if user_ser.is_valid():
            user = user_ser.user
            token = user_ser.token
            self.back_dict["token"] = token
            self.back_dict["msg"] = "登陆成功"
            self.back_dict["username"] = user.username
            return Response(self.back_dict)
        else:
            self.back_dict["code"] = 101
            self.back_dict["msg"] = user_ser.errors

            return Response(self.back_dict)

【路由】

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.UserView.as_view({
        "post": "login"
    })),
]

【配置文件】

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework'
]


LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

AUTH_USER_MODEL = 'app01.UserInfo'