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

Posted XxMa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了drf多方式登录接口(手机号邮箱验证码)登录相关的知识,希望对你有一定的参考价值。

题目

##### 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\')),
]

短信验证登录实现流程

短信验证登陆

1. 以电话号码为参数调用发送验证登录短信的后台接口

2. 后台接口生成4位或者6位的数字验证码

3. 将生成的验证码和手机号码以key-value方式放入缓存(比如redis),并设置好缓存有效时间

4. 调用发送模板短信方法(或者第三方短信运营商接口)发送短信

5. 点击触发登陆,以电话号码和验证码为参数,调用后台登录验证接口

6. 后台登录验证接口校验缓存中对应保留的信息

如果一致,返回登陆成功;
否则返回失败原因


注意点:

  1. 一定要设置好验证码有效时间

  2. 限制发送验证码的时间间隔和每日次数


以上是关于drf多方式登录接口(手机号邮箱验证码)登录的主要内容,如果未能解决你的问题,请参考以下文章

试过用验证码登录NAS吗?

SpringBoot轻轻松松搞定用户邮箱登录注册

SpringBoot轻轻松松搞定用户邮箱登录注册

谷歌验证数字在哪里点

短信验证登录实现流程

发送短信验证码和邮箱验证码—Java实现