短信功能
腾讯云短信服务
"""
0、注册微信公众号平台
1、注册开发者账号
2、创建短信应用
3、创建签名与模板
"""
短信功能不封装
导入腾讯云短信接口pip install qcloudsms_py
# 短信应用 SDK AppID
appid = 1400303014 # SDK AppID 以1400开头
# 短信应用 SDK AppKey
appkey = "fe256e50a2d3e8d3cd07f21c42802ad3"
# 短信模板ID,需要在短信控制台中申请
template_id = 517040 # NOTE: 这里的模板 ID`7839`只是示例,真实的模板 ID 需要在短信控制台中申请
# 签名,参数使用的是`签名内容`
sms_sign = "小阿峰啊公众号" # NOTE: 签名参数使用的是`签名内容`,而不是`签名ID`。这里的签名"腾讯云"只是示例,真实的签名需要在短信控制台中申请
from qcloudsms_py import SmsSingleSender
sender = SmsSingleSender(appid, appkey)
import random
def get_code():
code=''
for i in range(6):
code+=str(random.randint(0,9))
return code
code=get_code()
print(code)
# params = ["5678", 5] # 当模板没有参数时,`params = []`
# 需要发送短信的手机号码
mobile = "17356530633"
try:
response = sender.send_with_param(86, mobile,template_id,(code,5) , sign=sms_sign, extend="", ext="")
if response and response.get('result')==0:
print('ok')
print(response)
except Exception as e:
print(e)
短信功能的二次封装
libs/tx_sms/settings.py
# 短信应用 SDK AppID
APP_ID = 1400303014 # SDK AppID 以1400开头
# 短信应用 SDK AppKey
APP_KEY = "fe256e50a2d3e8d3cd07f21c42802ad3"
# 短信模板ID,需要在短信控制台中申请
TEMPLATE_ID = 517040 # NOTE: 这里的模板 ID`7839`只是示例,真实的模板 ID 需要在短信控制台中申请
# 签名,参数使用的是`签名内容`
SMS_SIGN = "小阿峰啊公众号" # NOTE: 签名参数使用的是`签名内容`,而不是`签名ID`。这里的签名"腾讯云"只是示例,真实的签名需要在短信控制台中申请
libs/tx_sms/sms.py
import random
# 获取六位数字验证码
def get_sms_code():
code = ''
for i in range(6):
code += str(random.randint(0, 9))
return code
from qcloudsms_py import SmsSingleSender
from .sesttings import APP_ID, APP_KEY, TEMPLATE_ID, SMS_SIGN
sender = SmsSingleSender(APP_ID, APP_KEY)
from utils.logging import logger
def send_sms(mobile, code, exp):
try:
response = sender.send_with_param(86, mobile, TEMPLATE_ID, (code, exp), sign=SMS_SIGN, extend="", ext="")
if response and response.get('result') == 0:
return True
logger.error('短信发送失败,状态码:%s,错误信息:%s' % (response.get('result'), response.get('errmsg')))
except Exception as e:
logger.error('短信发送异常,异常信息:%s' % e)
return False
libs/tx_sms/__init__.py
from .sms import get_sms_code,send_sms
调用
from libs import tx_sms
code=tx_sms.get_sms_code()
print(code)
result=tx_sms.send_sms('17356530633',code,5)
if result:
print('发送成功')
多方式登录
视图层
import re
from rest_framework.views import APIView
from . import serializers
from utils.response import APIResponse
# Create your views here.
# 多方式登录
class LoginAPIView(APIView):
#认证权限一定要局部禁用
authentication_classes = ()
permission_classes = ()
def post(self,request,*args,**kwargs):
serializer=serializers.LoginModelSerializer(data=request.data)
serializer.is_valid(raise_exception=True)# 内部在全局钩子中完成token的签发
return APIResponse(results={
'username':serializer.content.get('user').username,
'token':serializer.content.get('token')
})
序列化
import re
from rest_framework import serializers
from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler
from . import models
class LoginModelSerializer(serializers.ModelSerializer):
#post请求,序列化默认当做create动作进行校验,需要校验数据库,create动作username会抛用户已存在异常
#抛用户已存在异常是多余的,所有自定义系统校验规则即可
username=serializers.CharField(min_length=3,max_length=16)
password=serializers.CharField(min_length=3,max_length=16)
class Meta:
model=models.User
fields=('username','password')
#用全局钩子,完成token的签发
def validate(self, attrs):
#通过username和password完成多方式登录校验,得到user对象
user=self._validata_user(attrs)
#user对象包装payload载荷
payload=jwt_payload_handler(user)
#payload载荷签发token
token=jwt_encode_handler(payload)
#将user与token存储到serilizer对象中,方便在视图类中使用
self.content={
'user':user,
'token':token
}
return attrs
def _validata_user(self,attr):
username=attr.get('username')
password=attr.get('password')
if re.match(r'.*@.*',username):#邮箱
user=models.User.objects.filter(email=username).first()
elif re.match(r'^1[3-9][0-9]{9}$',username):#电话
user=models.User.objects.filter(mobile=username).first()
else:#用户名
user=models.User.objects.filter(username=username).first()
if not user or not user.check_password(password):
raise serializers.ValidationError({'message':'用户信息异常'})
return user
验证码发送
视图层
#发送验证码
from libs import tx_sms
from django.core.cache import cache
from django.conf import settings
class SMSAPIView(APIView):
authentication_classes = ()
permission_classes = ()
def post(self, request, *args, **kwargs):
#处理手机号
mobile=request.data.get('mobile',None)
if not mobile:
return APIResponse(1, msg='mobile字段必须', http_status=400)
if not re.match(r'^1[3-9][0-9]{9}$',mobile):
return APIResponse(1, msg='mobile格式有误', http_status=400)
#生成验证码
code=tx_sms.get_sms_code()
#发送验证码
result=tx_sms.send_sms(mobile,code,settings.SMS_EXP//60)
if not result:
return APIResponse(1, msg='验证码发送失败')
#缓存验证码
print(settings.SMS_EXP)
cache.set(settings.SMS_CACHE_FORMAT % mobile,code,settings.SMS_EXP)
#成功响应
return APIResponse(0,msg='验证码发送成功')
const.py
# 短信验证码缓存key
SMS_CACHE_FORMAT = 'sms_cache_%s'
# 短信过期时间s
SMS_EXP = 3000000
手机登录
视图层
# 手机验证码登录
class LoginMobileAPIView(APIView):
# 认证权限一定要局部禁用
authentication_classes = ()
permission_classes = ()
def post(self, request, *args, **kwargs):
serializer = serializers.LoginMobileModelSerializer(data=request.data)
serializer.is_valid(raise_exception=True) # 内部在全局钩子中完成token的签发
return APIResponse(results={
'username': serializer.content.get('user').username,
'token': serializer.content.get('token')
})
序列化
from django.core.cache import cache
from django.conf import settings
class LoginMobileModelSerializer(serializers.ModelSerializer):
mobile=serializers.CharField(min_length=11,max_length=11)
code=serializers.CharField(min_length=6,max_length=6)
class Meta:
model=models.User
fields=('mobile','code')
#验证码格式内容有误就不需要进行 取服务器存储的验证码(IO操作)进行校验
def validate_code(self,value):
try:
int(value)
return value
except:
raise serializers.ValidationError('验证码有误')
def validate(self, attrs):
mobile=attrs.get('mobile')
code=attrs.pop('code')
#那服务器缓存的验证码
old_code=cache.get(settings.SMS_CACHE_FORMAT % mobile)
if code!=old_code:
raise serializers.ValidationError({'code': '验证码有误'})
try:
user = models.User.objects.get(mobile=mobile, is_active=True)
except:
raise serializers.ValidationError({'mobile': '该用户不存在'})
payload=jwt_payload_handler(user)
token=jwt_encode_handler(payload)
self.content = {
'user': user,
'token': token
}
return attrs