登录接口分析
登录分为多方式登录和验证码登录方式
多方式登录
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)
来源:https://www.cnblogs.com/suncolor/p/16853710.html
本站部分图文来源于网络,如有侵权请联系删除。