Django+Vue3前后端分离学习(四)(登录功能实现)

1、序列化数据:

创建serializers.py的python文件

从rest_framework里导入serializers类:

复制代码
from rest_framework import serializers

class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True, error_messages={"required": "请输入邮箱!"})
    password = serializers.CharField(max_length=20, min_length=6)

    # 重写校验
    def validate(self, attrs):
        email = attrs.get('email')
        password = attrs.get('password')

        if email and password:
            user = OAUser.objects.filter(email=email).first()
            if not user:
                raise serializers.ValidationError("请输入正确的邮箱!")
            if not user.check_password(password):
                raise serializers.ValidationError("请输入正确的密码!")
            # 判断状态
            if user.status == UserStatusChoices.UNACTIVE:
                raise serializers.ValidationError("该用户尚未激活!")
            elif user.status == UserStatusChoices.LOCKED:
                raise serializers.ValidationError("该用户已被锁定,请联系管理员!")
            # 为了节省执行SQL语句的次数,这里我们把user直接放到attrs中,方便在视图中使用
            attrs['user'] = user
        else:
            raise serializers.ValidationError('请传入邮箱和密码!')
        return attrs

2、创建authentications.py文件

安装jwt:

复制代码
pip install PyJWT

import jwt
import time
from django.conf import settings
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework import exceptions
from jwt.exceptions import ExpiredSignatureError
from .models import OAUser


def generate_jwt(user):
    expire_time = time.time() + 60 * 60 * 24 * 7
    return jwt.encode({"userid": user.pk, "exp": expire_time}, key=settings.SECRET_KEY)


class UserTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 这里的request:是rest_framework.request.Request对象
        return request._request.user, request._request.auth


class JWTAuthentication(BaseAuthentication):
    keyword = 'JWT'

    def authenticate(self, request):
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != self.keyword.lower().encode():
            return None

        if len(auth) == 1:
            msg = "不可用的JWT请求头!"
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = '不可用的JWT请求头!JWT Token中间不应该有空格!'
            raise exceptions.AuthenticationFailed(msg)

        try:
            jwt_token = auth[1]
            jwt_info = jwt.decode(jwt_token, settings.SECRET_KEY, algorithms='HS256')
            userid = jwt_info.get('userid')
            try:
                # 绑定当前user到request对象上
                user = OAUser.objects.get(pk=userid)
                setattr(request,'user', user)
                return user, jwt_token
            except:
                msg = '用户不存在!'
                raise exceptions.AuthenticationFailed(msg)
        except ExpiredSignatureError:
            msg = "JWT Token已过期!"
            raise exceptions.AuthenticationFailed(msg)

3、登录的话涉及增删改查,所以直接用rest_framework提供的APIView

导入:

复制代码
from rest_framework.views import APIView
from .serializers import LoginSerializer, UserSerializer
from .authentications import generate_jwt
from rest_framework.response import Response

class LoginView(APIView):
    def post(self, request):
        # 1. 验证数据是否可用
        serializer = LoginSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.validated_data.get('user')
            user.last_login = datetime.now()
            user.save()
            # 生成token
            token = generate_jwt(user)
            return Response({'token': token, 'user': UserSerializer(user).data})
        else:
            # person = {"username": "张三", "age": 18}
            # person.values() = ['战三', 18] dict_values
            detail = list(serializer.errors.values())[0][0]
            # drf在返回响应是非200的时候,他的错误参数名叫detail,所以我们这里也叫做detail
            return Response({"detail": detail}, status=status.HTTP_400_BAD_REQUEST)

User对象实例化 使用serializers.ModelSerializer:

复制代码
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = 0AUser
        fields = "__all__"

嵌套定义:

复制代码
class DepartmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = OADepartment
        fields = "__all__"


class UserSerializer(serializers.ModelSerializer):
    department = DepartmentSerializer()
    class Meta:
        model = OAUser
        # fields = "__all__"
        exclude = ('password', 'groups', 'user_permissions')
相关推荐
Da Da 泓9 分钟前
多线程(四)【线程安全问题】
java·开发语言·jvm·学习·安全·多线程·线程安全问题
羽沢319 分钟前
一些css属性学习
前端·css·学习
桂花饼11 分钟前
[首发实测] GPT-5.2 pro 接入指南:SWE-bench 80% 胜率的“工程级”模型,Python 如何实现低成本调用?
python·gpt·ai编程·大模型实战·gemini 3 pro·claude opus 4.5
LUU_7912 分钟前
Day37 深入理解SHAP图
python
走在路上的菜鸟17 分钟前
Android学Dart学习笔记第十四节 库和导库
android·笔记·学习·flutter
好奇龙猫19 分钟前
【AI学习-comfyUI学习-第十七六节-SUPIR放大(XL模型专属)-各个部分学习-记录】
人工智能·学习
windfantasy199022 分钟前
青少年编程考级:建立学习目标,提升综合素养的有效途径
人工智能·学习·青少年编程
李星星BruceL24 分钟前
Pytest第三章(参考指南1)
python·自动化·pytest
哎呀呦呵25 分钟前
pytest基本使用
python·pytest
阿关@26 分钟前
Vscode中Python无法将pip/pytest”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
vscode·python·pip