手动签发token(多方式登录:用户名、手机号、邮箱)

发布时间 2023-11-02 20:50:57作者: PiggThird

要求登陆数据格式

# 使用用户名,手机号,邮箱,都可以登录#
# 前端需要传的数据格式
{	    用户名 / 手机号 / 邮箱
"username":"lqz/1332323223/33@qq.com",
"password":"lqz12345"
}

序列化类中 ser.py

from rest_framework import serializers
import re
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.utils import jwt_encode_handler, jwt_payload_handler
from api import models


class LoginModelSerializer(serializers.ModelSerializer):
    username = serializers.CharField()  # 重新覆盖username字段,数据中它是unique,post请求会认为你保存数据,自己有校验没过
    # 或者你不想覆盖就把下面的fields里面的username改成别的名字 name
    class Meta:
        model = models.User
        fields = ['username', 'password']

    def validate(self, attrs):
        username = attrs.get('username')    # 用户名有三种格式
        password = attrs.get('password')
        # 在这写逻辑
        # 通过判断,username数据不同,查询字段不一样
        # 正则匹配,如果是手机号
        if re.match('^1[3-9][0-9]{9}$', username):
            user = models.User.objects.filter(phone=username).first()
        # 如果是邮箱
        elif re.match('^.+@.+$', username):
            user = models.User.objects.filter(email=username).first()
        # 否则就是用户名
        else:
            user = models.User.objects.filter(username=username).first()
        if user:
            # 用户存在 校验密码 因为密码是密文 要用check_password
            if user.check_password(password):
                # 签发token
                payload = jwt_payload_handler(user)  # 把user传入,得到payload
                token = jwt_encode_handler(payload)  # 把payload传入,得到token
                self.context['token'] = token
                self.context['username'] = user.username
                return attrs
            else:
                raise ValidationError('密码错误')
        else:
            raise ValidationError('用户不存在')

视图函数 views.py

# 手动签发token,完成多方式登录
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin, ViewSet
from app02 import ser
# class Login2View(ViewSetMixin, APIView):  # ViewSet(ViewSetMixin, views.APIView)
class Login2View(ViewSet):  # 上面两个可以直接用内置的ViewSet代替
    def login(self, request):
        # 1 需要有个序列化的类
        login_ser = ser.LoginModelSerializer(data=request.data)   # 这里要注意写上data 不写默认传给instance 报错
        # 2 生成序列化类对象
        # 3 调用序列化类对象的
        login_ser.is_valid(raise_exception=True)
        # 4 return
        token = login_ser.context.get('token')
        username = login_ser.context.get('username')
        return Response({'status': 100, 'msg': '登陆成功', 'token': token, 'username': username})