目录
第一步:在发送短信平台注册账号
具体步骤戳这里
第二步:新建一个包具体文件夹目录结构如下
前提条件是要下第三方模块,具体步骤戳这里
之后我们开始封装功能
send_sms_v3 包
__init__.py # 导入给外部使用的函数
settings.py # 配置信息
sms.py # 核心:获取n位数字验证码
1. init.py代码
from .sms import get_code, send_sms
1. settings.py代码
点击查看代码
SECRET_ID = '密钥key值'
SECRET_KEY = '密钥value值'
APP_ID = 'APP的id编号'
SIGN_NAME = '签名'
TEMPLATE_ID = '模板id'
2. sms.py代码
点击查看代码
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sms.v20210111 import sms_client, models
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from . import settings
import random
import json
# 产生随机验证码的函数
def get_code(number=4):
code = ''
for i in range(number):
code += str(random.randint(0, 9))
return code
# 发送短信函数
def send_sms(code, mobile):
try:
cred = credential.Credential(settings.SECRET_ID, settings.SECRET_KEY)
httpProfile = HttpProfile()
httpProfile.reqMethod = "POST"
httpProfile.reqTimeout = 30
httpProfile.endpoint = "sms.tencentcloudapi.com" # 指定接入地域域名(默认就近接入)
clientProfile = ClientProfile()
clientProfile.signMethod = "TC3-HMAC-SHA256" # 指定签名算法
clientProfile.language = "en-US"
clientProfile.httpProfile = httpProfile
client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)
req = models.SendSmsRequest()
req.SmsSdkAppId = settings.APP_ID
req.SignName = settings.SIGN_NAME
req.TemplateId = settings.TEMPLATE_ID
req.TemplateParamSet = [code, "30"]
req.PhoneNumberSet = ["+86" + mobile,]
req.SessionContext = ""
req.ExtendCode = ""
req.SenderId = ""
resp = client.SendSms(req)
res = json.loads(resp.to_json_string(indent=2))
if res.get('SendStatusSet')[0].get('Code') == 'Ok':
return True
else:
return False
except TencentCloudSDKException as err:
print(err)
return False
第三:写了发送短信的接口
1. 视图类
点击查看代码
from libs.send_sms_v3 import get_code, send_sms as send_sms_ss
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action
from rest_framework.exceptions import APIException
from common_response import APIResponse
from .serializer import UserLoginSerializer, UserMobileLoginSerializer
from .models import User
from django.utils.datastructures import MultiValueDictKeyError
from django.core.cache import cache
from threading import Thread
class UserView(GenericViewSet):
serializer_class = UserLoginSerializer
queryset = User.objects.all().filter(is_active=True)
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
try:
# 从地址栏中取出手机号 query_params : queryDict
mobile = request.query_params['mobile']
User.objects.get(mobile=mobile)
except MultiValueDictKeyError as e:
raise APIException('手机号格式不对')
except Exception as e:
return APIException
return APIResponse(msg='手机号已存在')
@action(methods=['POST'], detail=False)
def login_mul(self, request, *args, **kwargs):
return self._login(request, *args, **kwargs)
@action(methods=['POST'], detail=False)
def send_sms(self, request):
try:
mobile = request.data['mobile']
# 生成验证码
code = get_code()
cache.set('sms_code_%s' % mobile, code)
# 使用异步发送短信
t = Thread(target=send_sms_ss, args=[code, mobile])
t.start()
return APIResponse(msg='短信已发送')
except Exception as e:
raise APIException(str(e))
# 重写get_serializer_class方法
def get_serializer_class(self):
if self.action == 'login_sms':
return UserMobileLoginSerializer
else:
return super().get_serializer_class()
def _login(self, request, *args, **kwargs):
ser = self.get_serializer(data=request.data)
ser.is_valid(raise_exception=True)
token = ser.context.get('token')
username = ser.context.get('username')
return APIResponse(token=token, username=username)
@action(methods=['POST'], detail=False)
def login_sms(self, request, *args, **kwargs):
return self._login(request)
2. 序列化类
点击查看代码
from .models import User
from rest_framework import serializers
from rest_framework.exceptions import APIException
from rest_framework_jwt.settings import api_settings
from django.core.cache import cache
import re
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class BaseUserSerializer():
def validate(self, attrs):
user = self._get_user(attrs)
token = self._get_token(user)
self.context['token'] = token
self.context['username'] = user.username
return attrs
def _get_user(self, attrs):
raise Exception('需要重写该方法')
def _get_token(self, user):
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return token
class UserLoginSerializer(BaseUserSerializer, serializers.ModelSerializer):
# 重写username字段,把原来的校验规则去掉
username = serializers.CharField()
class Meta:
model = User
fields = ['username', 'password']
def _get_user(self, attrs):
username = attrs.get('username')
password = attrs.get('password')
if re.match(r'^1[3-9][0-9]{9}$', username):
user = User.objects.filter(phone=username).first()
elif re.match(r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$', username):
user = User.objects.filter(email=username).first()
else:
user = User.objects.filter(username=username).first()
if user and user.check_password(password):
return user
else:
raise APIException('用户名不存在或密码错误')
class UserMobileLoginSerializer(BaseUserSerializer, serializers.ModelSerializer):
code = serializers.CharField()
mobile = serializers.CharField()
class Meta:
model = User
fields = ['mobile', 'code']
def _get_user(self, attrs):
code = attrs.get('code')
mobile = attrs.get('mobile')
# 从缓存中取出
old_code = cache.get('sms_code_%s' % mobile)
if old_code and old_code == code:
user = User.objects.filter(mobile=mobile).first()
if user:
return user
else:
raise APIException('用户不存在')
else:
raise APIException('验证码验证失败')
3. 路由
点击查看代码
# 分路由
from rest_framework.routers import SimpleRouter
from . import views
router = SimpleRouter()
router.register('userinfo', views.UserView, 'userinfo')
urlpatterns = [
]
urlpatterns += router.urls
# 总路由
from django.urls import path, include
urlpatterns = [
path('api/v1/user/', include('user.urls')),
]
# 访问
http://127.0.0.1:8000/api/v1/user/userinfo/send_sms/
# {"mobile":"输入手机号"} 发送POST请求 即可测试