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')
相关推荐
青 春 记 忆5 小时前
零基础入门Python11|Git实战:为任务管理器建立版本历史
开发语言·git·vscode·python·python3.11
Python私教5 小时前
多个项目怎么安全合并?先适配,再切换
后端·python·架构
Shaoxi Zhang6 小时前
JAVA学习笔记035——对象和JSON格式
java·笔记·学习
陈皮波比茶6 小时前
Redis学习
数据库·redis·学习
北斗落凡尘7 小时前
LangGraph 入门实战(12)--使用MCP
后端·python·langchain
jdksjw7 小时前
同步与异步、阻塞与非阻塞、多线程、协程超详细讲解(Python并发编程从入门到精通)
开发语言·python
Mike_Zhang8 小时前
使用python统计FreeSWITCH呼叫并发
python·freeswitch
SL-staff8 小时前
技术实践:HR如何用JVS-Logic可视化编排实现考勤数据同步(含节点配置与异常处理)
开发语言·python·低代码·钉钉·可视化编排·jvs-logic·hr技术
minglie19 小时前
espidf的esp32版的webClient
学习
学运维的Kysan9 小时前
暑假运维学习打卡第二十五天8.16
学习