登录接口分析
登录分为多方式登录和验证码登录方式
多方式登录
- 1)前台提供账号密码,账号可能是 用户名、手机号、邮箱等
- 接口:
- 后台只需要提供一个多方式登录接口即可 - 多方式登录接口
复制代码 多方式登录接口
前端输入完账号和密码,点击登录,向后端发送请求进行校验用户登录数据
urls.py- from django.urls import path,re_path,include
- from rest_framework.routers import SimpleRouter
- from user import views
- router = SimpleRouter()
- router.register('',views.LoginView,'login')
- urlpatterns = [
- path('',include(router.urls)),
- ]
复制代码 views.py- from rest_framework.viewsets import ViewSet
- from user import serializers
- from luffyapi.utils.response import APIResponse
- from rest_framework.decorators import action
- class LoginView(ViewSet):
- # 密码方式登录接口
- @action(methods=['POST'],detail=False) # 加入action装饰器,自动生成路由
- def login(self,request,*args,**kwargs):
- # 把前端传入的用户登录数据传入序列化器
- ser = serializers.UserModelserialize(data=request.data)
- # 判读传入的数据是否合法
- if ser.is_valid():
- # 合法获取token和用户名
- token =ser.context['token']
- username = ser.context['user'].username
- # 然后返回给前端
- return APIResponse(token=token,username=username)
- else:
- return APIResponse(code='0',msg=ser.errors)
复制代码 serializes.py- from rest_framework import serializers
- from user import models
- from rest_framework.exceptions import ValidationError
- class UserModelserialize(serializers.ModelSerializer):
- username = serializers.CharField() # ?
- class Meta:
- model = models.UserInfo
- fields = ['username','password','id']
- extra_kwargs = {
- 'id':{'read_only':True},
- 'password': {'write_only': True},
- }
- def validate(self, attrs):
- # 多种方式登录
- user = self._get_user(attrs)
- # 签发token
- token = self._get_token(user)
- # 放到context中,我在视图函数中可以取出来
- self.context['token'] = token
- self.context['user'] = user
- return attrs
- # 校验前端发来的数据
- def _get_user(self, attrs):
- # 获取前端发送的数据
- username = attrs.get('username')
- password = attrs.get('password')
- import re
- # 校验前端的用户是否为手机号、邮箱、用户名登录
- if re.match('^1[3-9][0-9]{9}$',username):
- user = models.UserInfo.objects.filter(telephone=username).first()
- elif re.match('^.+@.+$',username):
- user = models.UserInfo.objects.filter(email=username).first()
- else:
- user = models.UserInfo.objects.filter(username=username).first()
- # 用户名存在,则校验密码
- if user:
- ret = user.check_password(password)
- if ret:
- return user
- else:
- raise ValidationError('密码错误')
- else:
- raise ValidationError('用户名不存在')
- # 签发token函数,前面加一个_暗示内部使用的
- def _get_token(self,user):
- from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler
- pyload = jwt_payload_handler(user) #通过user对象获取pyload
- token = jwt_encode_handler(pyload) #通过pyload获取token
- return token
复制代码 验证码登录
验证码可以保存在redis里,也可以保存在缓存里- 1)前台提供手机号和验证码完成登录
- 接口:
- 前台填完手机号,往后台发送校验手机号的请求,如果存在继续,不存在提示注册 - 手机号存在与否接口
- 前台点击发送验证码,将手机再次发送给后台,后台将手机号通知给第三方,发送短信 - 手机验证码接口
- 前台点击登录提交手机号与验证码,完成验证码登录 - 验证码登录接口
复制代码 手机号是否存在的接口设计- # 校验手机号是否存在接口
- @action(methods=['GET'], detail=False)
- def check_telephone(self, request, *args, **kwargs):
- telephone = request.GET.get('telephone')
- if not re.match('^1[3-9][0-9]{9}$',telephone):
- return APIResponse(code=0,msg='手机号不合法')
- try:
- models.UserInfo.objects.get(telephone=telephone)
- return APIResponse()
- except:
- return APIResponse(code=0,msg='手机号不存在')
复制代码 发送验证码接口- from luffyapi.libs.tx_msg import get_code,send_message # 导入封装好的短信接口
- from django.core.cache import cache # 导入缓存
- from django.conf import settings
- # 发送验证码接口
- @action(methods=['GET'], detail=False)
- def send(self,request,*args,**kwargs):
- telephone = request.GET.get('telephone')
- if not re.match('^1[3-9][0-9]{9}$',telephone):
- return APIResponse(code=0,msg='手机号不合法')
- code = get_code() #获取随机验证码
- result = send_message(telephone,code)
- # 将验证码保存到缓存中备用,参数分别是key,value,过期时间秒
- # 这个telephone可以有标识一点,在settings进行配置一下
- cache.set(settings.CACHE_MSG % telephone,code,180)
- # 如果result返回true
- if result:
- return APIResponse(msg='验证码发送成功')
- else:
- return APIResponse(code=0,msg='验证码发送失败')
复制代码 短信发送频率限制
写一个throttlings.py- from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
- # 写一个类继承SimpleRateThrottle
- class TimeThrottling(SimpleRateThrottle):
- scope = 'sms'
- def get_cache_key(self, request, view):
- telephone = request.query_params.get('telephone')
- return self.cache_format%{'scope':'sms','ident':telephone} # 以手机号返回不太好,换一种不易重名的返回做限制
复制代码 在settings里配置一下频率- REST_FRAMEWORK = {
- 'DEFAULT_THROTTLE_RATES': {
- 'sms': '1/m' # 一分钟访问1次
- }
- }
复制代码 views.py- from . import throttlings
- class SendView(ViewSet):
- # 发送短信频率限制
- throttle_classes = [throttlings.TimeThrottling]
- # 发送验证码接口
- @action(methods=['GET'], detail=False)
- def send(self,request,*args,**kwargs):
- telephone = request.query_params.get('telephone')
- if not re.match('^1[3-9][0-9]{9}$',telephone):
- return APIResponse(code=0,msg='手机号不合法')
- code = get_code() #获取随机验证码
- result = send_message(telephone,code)
- # 将验证码保存到缓存中备用,参数分别是key,value,过期时间秒
- # 这个telephone可以有标识一点,在settings进行配置一下
- cache.set(settings.CACHE_MSG % telephone,code,180)
- # 如果result返回true
- if result:
- return APIResponse(msg='验证码发送成功')
- else:
- return APIResponse(code=0,msg='验证码发送失败')
复制代码 手机号登陆接口
serializes.py
作用:对前端发来的手机号和验证码进行校验,并签发token- class UserCodeModelserialize(serializers.ModelSerializer):
- code = serializers.CharField(max_length=4,min_length=4)
- class Meta:
- model = models.UserInfo
- fields = ['telephone','code']
- # 这里因为手机号验证码方式登录也需要校验和签发token,所以也需要重写validate方法
- def validate(self, attrs):
- user = self._get_user(attrs)
- token = self._get_token(user)
- self.context['user'] = user
- self.context['token'] = token
- return attrs
- def _get_user(self, attrs):
- # 获取前端发送的数据
- telephone = attrs.get('telephone')
- code = attrs.get('code')
- # 取出生产的code与用户传的code做比较
- cache_code = cache.get(settings.CACHE_MSG%telephone)
- if cache_code == code:
- user = models.UserInfo.objects.filter(telephone=telephone).first()
- if user:
- cache.set(settings.CACHE_MSG%telephone,'')
- return user
- else:
- raise ValidationError('用户不存在')
- else:
- raise ValidationError('验证码不正确')
- # 签发token函数,前面加一个_暗示内部使用的
- def _get_token(self,user):
- from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler
- pyload = jwt_payload_handler(user) #通过user对象获取pyload
- token = jwt_encode_handler(pyload) #通过pyload获取token
- return token
复制代码 views.py- # 验证码方式登录接口
- @action(methods=['POST'], detail=False)
- def code_login(self, request, *args, **kwargs):
- # 把前端传入的用户登录数据传入序列化器
- ser = serializers.UserCodeModelserialize(data=request.data)
- # 判读传入的数据是否合法
- if ser.is_valid():
- # 合法获取token和用户名
- token = ser.context['token']
- username = ser.context['user'].username
- # 然后返回给前端
- return APIResponse(token=token, username=username)
- else:
- return APIResponse(code='0', msg=ser.errors)
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |