drf多方式登录接口(手机号、邮箱、验证码)登录

发布时间 2023-06-01 14:59:31作者: 抱紧小洪

题目

##### 3 多方式登录接口####
	-使用auth的user表扩写
	-用户名+密码
    -手机号+密码
    -邮箱+密码 
    
    -签发token逻辑,放在序列化类中写

方式一:

serializer.py

from rest_framework import serializers
from .models import UserInfo
from rest_framework.exceptions import ValidationError
import re

from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

class UserSerializer(serializers.ModelSerializer):
    username = serializers.CharField()  # 这个优先用这个,就不是映射过来的,就没有unique的限制了
    class Meta:
        model = UserInfo
        # 大坑:继承ModelSerializer后,fields的字段是映射过来的
        # username 是unique唯一的,反序列化校验的时候,字段自己的规则,会去数据库查询有没有这个用户,如果有,直接报错了
        fields = ['username','password']  # 只做反序列化的校验

    # 这个东西的返回值必须是个字典,校验过后的数据
    def validate(self,attrs):  # attr是前端传入的,校验过后的数据,先校验字段自己的然后局部钩子最后全局钩子
        # 1.获取前端传入的数据
        username = attrs.get('username')
        password = attrs.get('password')
        # 2.查用户是否存在(先查出用户再校验密码,查用户有三种类型:手机号,邮箱,用户名)
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = UserInfo.objects.filter(phone=username).first()
        elif re.match(r'^.+@.+$', 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('用户名或密码错误')

views.py

from rest_framework.viewsets import ViewSet
from .serializer import UserSerializer
from rest_framework.response import Response

class UserView(ViewSet):
    def login(self,request):
        # 1 得到一个序列化类
        ser = UserSerializer(data=request.data)
        if ser.is_valid():  # 执行全局钩子
            user = ser.user
            token = ser.token
            return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username})
        else:
            return Response({'code': 100, 'msg': ser.errors})

urls.py

path('login/',views.UserView.as_view({'post':'login'}))

方式二:

serializer.py

from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from rest_framework import serializers
from django.contrib.auth import authenticate

class UserSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

    def validate(self, attrs):
        credentials = {
            'username':attrs.get('username'),
            'password': attrs.get('password')
        }

        if all(credentials.values()):
            user = authenticate(**credentials)
            if user:
                if not user.is_active:
                    msg = '滚蛋'
                    raise serializers.ValidationError(msg)

                payload = jwt_payload_handler(user)
                token = jwt_encode_handler(payload)
                self.token = token
                return {
                    'token':token,
                    'user': user
                }
            else:
                msg = '用户名密码错误'
                raise serializers.ValidationError(msg)
        else:
            msg = '必须填写用户名和密码'
            raise serializers.ValidationError(msg)

backends.py

from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from .models import UserInfo

class LoginBackend(ModelBackend):
    # 校验规则可以自己写
    def authenticate(self, request, username=None, password=None, **kwargs):
        user = UserInfo.objects.get(Q(username=username) | Q(phone=username) | Q(email=username))
        if user is not None and user.check_password(password):
            return user

settings.py

AUTHENTICATION_BACKENDS = [
    'app01.backends.LoginBackend'
]

views.py

from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from .serializer import UserSerializer
from .jwt_response import common_response

class UserView(ViewSet):
    def login(self,request):
        ser = UserSerializer(data=request.data)
        if ser.is_valid():
            username = ser.validated_data.get('user')
            token = ser.validated_data.get('token')
            response_data = common_response(token, username, request)
            response = Response(response_data)
            return response
        return Response(ser.errors)

urls.py

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