https://www.django-rest-framework.org/
Django REST框架是一个功能强大且灵活的工具包,用于构建Web API。
您可能希望使用REST框架的一些原因:
Redis 是完全开源免费的,遵守BSD协议(五大开源协议中的一个),是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
速度
有要求, 需要设置过期时间
, 并且数据关系不复杂
Django默认提供的认证系统中,用户的认证机制依赖Session机制,我们在本项目中将引入JWT认证机制,将用户的身份凭据存放在Token中,然后对接Django的认证系统
项目分为:
项目采用技术
发送短信的接口,携带数据以路劲参数的形式,get应该返回当前请求资源的请求数据,在这里资源数据发送到手机上,不需要返回给前端页面,所以直接返回一个OK就可以
定义接口
请求方式 get
请求路径 以名词复数形式来写 短信验证码 sms_codes/
携带数据 mobile 有请求头部、请求体、json字符串、表单、路径参数等形式
返回结果 OK
json数据、表单数据统一用request.data来获取
前端根据接口
前端根据接口发送ajax请求,ajax.get(路径参数),ajax.get(“sms_codes/13111111111”)
Response.data
通过response.data接收请求结果
后端根据接口填写代码
class View(APIView):
def get(self,request,mobile) 以请求路劲的形式直接在括号里填入请求路径中需要的参数
# request.query_pramas 获取查询字符串
# request.data. # 获取请求体数据
# 序列化器
ser = Serializers() APIview直接使用序列化器来生成序列化器对象
ser= self.get_serialzier() GenrecAPIview
这俩个差不多,只要业务逻辑中不涉及分页、过滤俩个都可以使用,如果业务逻辑中涉及到分页和过滤处理的话,只能使用GenrecAPIview,因为只有GenrecAPIview才提供了分页、过滤属性,
# 生成短信验证码
# 保存短信验证码
# 发送短信
# 返回结果
class Serialzers(ModelSerializer)
序列化器选择,只要操作的字段和模型类没有关系,就选择Serializer
如果操作的字段和模型类有关系就使用ModelSerializer
sms_codes=serializer.CharField()
class Meta:
model=User
fields=('sms_codes','usernam','mobile') 字段指明时,给他显示出来就额可以了
def create(): ModelSerializer中这个方法已经实现过了,实现的逻辑是固定的,如果发现固定的业务逻辑不够用,可以将方法进行重写
如果不断刷新请求页面,后端也需要不断接受请求,如果受到恶意代码(写一个while循环,不断请求服务器,如果写多个线程,如100个,那么服务器同一时间要处理100个请求,如果请求过多,服务器承受不了就会蹦)的操作,会增加后端服务器的压力。可以通过限流解决,还可以通过时间进行判断。
短信验证码不需要长期存储,可以使用Redis数据库进行存储,指定一个缓存数据库来存储短信验证码,并设置过期时间。配置文件中配置缓存Redis数据库
判断60秒时在缓存中写入判断依据,
Redis数据库操作网站Redis.cn
使用随机数生成6位数短信验证码,将生成的短信验证码写入Redis数据库verify,使用setex这个方法将验证码写入,短信验证码首先想到随机数
导入人熔炼云通讯的包,然后在发送短信的代码中导入云通讯的模块实现发送短信功能CCP,发送短信时可能需要多次,所以将请求放入管道中,一次完成pipeline
管道原理
如果网络状态不好的话,回导致请求一直阻塞等待在这里,所以要解决这个问题需要用到celery异步任务队列,celery由broke(任务队列)、worker任务执行者可以去任务队列中找到方法,开辟一个线程去执行这个任务。
如何去调用队列中的方法,需要通过delay方法来通知worker来执行这个任务,worker会去任务队列中查询这个方法,如果有这个任务方法,就会开辟一个线程去执行这个任务。
celery使用需要单独创建一个文件夹,celery_tasks来使用,首先配置config
broker_url = "redis://127.0.0.1/14"
然后在main.py中配置,celery的启动文件
from celery import Celery
# 为celery使用django配置文件进行设置
import os
if not os.getenv('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = 'meiduo_mall.settings.dev'
# 创建celery应用
app = Celery('meiduo')
# 导入celery配置
app.config_from_object('celery_tasks.config')
# 自动注册celery任务 sms、email代表创建的目录名字,目录用来存放定义的任务
app.autodiscover_tasks(['celery_tasks.sms','celery_tasks.email','celery_tasks.html'])
# celery -A celery_tasks.main worker -l info
创建sms/tasks.py,tasks.py必须使用这个名字,创建完成后在main.py文件中添加sms这个任务’celery_tasks.sms’
注意点:添加了异步任务后需要在运行代码的时候,开启异步任务,不然会报无法连接,拒绝连接的错误
from meiduo_mall.libs.yuntongxun.sms import CCP
from celery_tasks.main import app
@app.task(name='send_sms_code')
def send_sms_code(mobile,sms_code):
ccp=CCP()
ccp.send_template_sms(mobile,[sms_code,'5'],1)
@app.task(name='a_print')
def a_print():
print(1111)
写完要在当前目录下配置路由,并且全局路由也需要匹配
# 全局路由 需要导入include
url(r'^', include('verifications.urls')),
from django.conf.urls import url
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^sms_codes/(?P1[3-9]\d{9})/$' , views.SMSCodeView.as_view()),
]
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from random import randint
from django_redis import get_redis_connection
from meiduo_mall.libs.yuntongxun.sms import CCP
from celery_tasks.sms.tasks import send_sms_code
# Create your views here.
class SMSCodeView(APIView):
def get(self, request, mobile):
# 判断60s
conn = get_redis_connection('verify')
flag = conn.get('sms_flag_%s' % mobile)
if flag:
return Response({'message': '请求过于频繁'}, status=400)
# 生成短信验证码
sms_code = '%06d' % randint(0, 999999)
print(sms_code)
# 保存短信验证码
pl = conn.pipeline()
pl.setex('sms_%s' % mobile, 300, sms_code)
pl.setex('sms_flag_%s' % mobile, 60, 1)
pl.execute() # 发送redis执行命令
# 发送短信
# ccp=CCP()
# ccp.send_template_sms(mobile,[sms_code,'5'],1)
send_sms_code.delay(mobile, sms_code)
# 返回结果
return Response({'message': 'ok'})
在代码中进行判断,如果频繁发送,返回请求过于频繁
判断用户名、手机号是否存在,通过用户名、手机号的数量来进行判断。如果存在显示存在,如果不存在显示不存在
首先安装
pip install django-cors-headers
在添加应用
INSTALLED_APPS = (
...
'corsheaders',
...
)
中间层设置
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...
]
添加白名单
# CORS
CORS_ORIGIN_WHITELIST = (
'127.0.0.1:8080',
'localhost:8080',
'www.meiduo.site:8080',
'api.meiduo.site:8000'
)
CORS_ALLOW_CREDENTIALS = True # 允许携带cookie
凡是出现在白名单中的域名,都可以访问后端接口
CORS_ALLOW_CREDENTIALS指明在跨域访问中,后端是否支持对cookie的操作。
密码加密使用set_password()对密码进行加密,还可以使用管理器方法进行加密
def create(self, validated_data):
del validated_data['sms_code']
del validated_data['password2']
del validated_data['allow']
# user=super().create(validated_data)
#
# # 密码加密
# user.set_password(validated_data['password'])
# user.save()
# 管理器方法 保存用户
user = User.objects.create_user(username=validated_data['username'], mobile=validated_data['mobile'],
password=validated_data['password'])
# 生成jwttoken
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
# d对user对象添加token属性字段
user.token = token
return user
登录需要状态保持
之前进行状态保持是使用session来记录的,在Django中使用token来记录,
Django中session的使用
Json Web Token认证机制
JWT(Json Web Token):一种在Web应用中安全传递信息的规范
一般是在请求头里加入Authorization,并加上Bearer标注:
fetch('api/user/1', {
headers: {
'Authorization': 'Bearer ' + token
}
})
JWT构成
写入session。
request.session['name']=python
获取session数据
Request.session.get('name')
session在服务器中保存形式。保存在redis中
以hash 类型进行保存
保存的形式是session的ID,session的ID实际上是一个随机字符串,随机字符串作为key值Ajshdjka123123:键值对{'name':'python'}
浏览器中保存形式。cookie
保存形式是键值对的形式保存
Sesssionid(键是sessionID):Ajshdjka123123(对应Redis中保存的key值)
用户注册接口:
1、短信验证接口
2、手机号判断是否存在
3、验证用户是否存在
4、验证两次密码输入是否相同
5、判断是否同意协议
6、保存用户注册信息
1、短信验证码
借助第三方平台容联云通讯实现发送短信功能
生成短信验证码
发送短信验证码
检查是否在60秒内有发送验证码记录
通过celery进行异步发送短信
校验短信验证码
验证后通过
前后端分离需要考虑跨域问题,使用了CORS 来解决跨域问题,在文件中配置访问的白名单实现跨域访问功能
celery实现异步发送短信,在发送短信过程中可能会出现等待时间过长(阻塞函数同时调用导致)、或者频繁发送短信的可能,这时候我们需要借助基于python开发的celery分布式任务队列的框架,来提高用户体验
记录用户注册或登录状态,我们不在使用session认证机制,而是采用了JWT(Json Web Token认证机制)认证机制,因为session是基于cookie来实现用户验证,cookie如果被截获,容易造成跨域请求伪造,而session又是存储在内存中,这样如果用户量增加会导致独立服务器无法承载更多的用户,如果使用token认证机制,就可以在请求时携带一个服务端提供的token值进行验证
JWT的构成
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
前端保存token
sessionStorage 浏览器关闭即失效
localStorage 长期有效
账号登录