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')
相关推荐
阿蒙Amon4 小时前
TypeScript学习-第1章:入门
javascript·学习·typescript
Hgfdsaqwr4 小时前
Django全栈开发入门:构建一个博客系统
jvm·数据库·python
开发者小天4 小时前
python中For Loop的用法
java·服务器·python
老百姓懂点AI5 小时前
[RAG实战] 向量数据库选型与优化:智能体来了(西南总部)AI agent指挥官的长短期记忆架构设计
python
A9better6 小时前
嵌入式开发学习日志50——任务调度与状态
stm32·嵌入式硬件·学习
非凡ghost7 小时前
ESET NupDown Tools 数据库下载工具
学习·软件需求
喵手7 小时前
Python爬虫零基础入门【第九章:实战项目教学·第15节】搜索页采集:关键词队列 + 结果去重 + 反爬友好策略!
爬虫·python·爬虫实战·python爬虫工程化实战·零基础python爬虫教学·搜索页采集·关键词队列
Suchadar7 小时前
if判断语句——Python
开发语言·python
ʚB҉L҉A҉C҉K҉.҉基҉德҉^҉大7 小时前
自动化机器学习(AutoML)库TPOT使用指南
jvm·数据库·python
喵手7 小时前
Python爬虫零基础入门【第九章:实战项目教学·第14节】表格型页面采集:多列、多行、跨页(通用表格解析)!
爬虫·python·python爬虫实战·python爬虫工程化实战·python爬虫零基础入门·表格型页面采集·通用表格解析