登录框直接显示在主页上,所以在components中写一格登录组件
X
登录|注册
老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活
![]()
- 免费课
- 实战课
- 轻课
登录|注册
密码登录短信登录登录 {{ sms_interval }}登录 立即注册
新用户注册{{ sms_interval }}注册 立即登录
sdk:https://cloud.tencent.com/document/product/382/43196#
# 1. 下载模块:pip install tencentcloud-sdk-python# -*- coding: utf-8 -*-
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的client models。
from tencentcloud.sms.v20210111 import sms_client, models# 导入可选配置类
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfiletry:cred = credential.Credential("AKIDTXcdXG6u5C9xxxxxxxxxD5VwPp", "LZgaKxTOI0VowxxxxxxvDKDtLcfWCiqm")httpProfile = HttpProfile()httpProfile.reqMethod = "POST" # post请求(默认为post请求)httpProfile.reqTimeout = 30 # 请求超时时间,单位为秒(默认60秒)httpProfile.endpoint = "sms.tencentcloudapi.com" # 指定接入地域域名(默认就近接入)# 非必要步骤:# 实例化一个客户端配置对象,可以指定超时时间等配置clientProfile = ClientProfile()clientProfile.signMethod = "TC3-HMAC-SHA256" # 指定签名算法clientProfile.language = "en-US"clientProfile.httpProfile = httpProfileclient = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)req = models.SendSmsRequest()req.SmsSdkAppId = "1400763090" # 腾讯短信创建app把app的id号复制过来https://console.cloud.tencent.com/smsv2/app-manage# 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名# 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看req.SignName = "XX公众号"# 模板 ID: 必须填写已审核通过的模板 ID# 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看req.TemplateId = "1603526"# 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空req.TemplateParamSet = ["8888",'100']# 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]# 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号req.PhoneNumberSet = ["8613711112222"]# 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回req.SessionContext = ""req.ExtendCode = ""req.SenderId = ""resp = client.SendSms(req)# 输出json格式的字符串回包print(resp.to_json_string(indent=2))except TencentCloudSDKException as err:print(err)
"""后期别的项目可能也需要发送短信;将发送短信的功能封装成包后,后续只需要调用包到项目中使用即可""""""
包的目录结构send_tx_sms # 包名__init__.pysettings.py # 配置文件sms.py # 核心代码
"""
from .sms import get_code,send_sms_by_phone
SECRET_ID = ''
SECRET_KEY = ''
APP_ID = ''
SIGN_NAME=''
TEMPLATE_ID=''
import randomfrom tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的client models。
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# 获取n位随机数组验证码的函数
def get_code(num=4):code = ''for i in range(num):random_num = random.randint(0, 9)code += str(random_num)return code# 发送短信函数
def send_sms_by_phone(mobile, code):try:cred = credential.Credential(settings.SECRET_ID, settings.SECRET_KEY)httpProfile = HttpProfile()httpProfile.reqMethod = "POST" # post请求(默认为post请求)httpProfile.reqTimeout = 30 # 请求超时时间,单位为秒(默认60秒)httpProfile.endpoint = "sms.tencentcloudapi.com" # 指定接入地域域名(默认就近接入)# 非必要步骤:# 实例化一个客户端配置对象,可以指定超时时间等配置clientProfile = ClientProfile()clientProfile.signMethod = "TC3-HMAC-SHA256" # 指定签名算法clientProfile.language = "en-US"clientProfile.httpProfile = httpProfileclient = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)req = models.SendSmsRequest()req.SmsSdkAppId = settings.APP_ID # 腾讯短信创建app把app的id号复制过来https://console.cloud.tencent.com/smsv2/app-manage# 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名# 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看req.SignName = settings.SIGN_NAME# 模板 ID: 必须填写已审核通过的模板 ID# 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看req.TemplateId = settings.TEMPLATE_ID# 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空req.TemplateParamSet = [code, '1']# 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]# 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号req.PhoneNumberSet = ["+86" + mobile, ]# 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回req.SessionContext = ""req.ExtendCode = ""req.SenderId = ""resp = client.SendSms(req)# 输出json格式的字符串回包# 字符串类型print(type(resp.to_json_string(indent=2)))return Trueexcept TencentCloudSDKException as err:return False
from libs.send_tx_sms import get_code, send_sms_by_phone
from django.core.cache import cacheclass UserView(ViewSet):@action(methods=['GET'], detail=False)def send_sms(self, request):mobile = request.query_params.get('mobile')if re.match(r'^1[3-9]\d{9}$', mobile): # 通过正则校验手机号code = get_code() # 获取随机验证码cache.set(f'sms_code_{mobile}', code) # 保存验证码到内存中res = send_sms_by_phone(mobile, code)if res:return APIResponse(msg='发送短信成功')else:# raise APIException('发送短信失败')return APIResponse(msg='发送短信失败', code=101)else:return APIResponse(msg='手机号不合法', code=102)
class UserView(ViewSet):def get_serializer(self, data):# 判断如果请求的action是:mul_login,返回UserMulLoginSerializer# 判断如果请求的action是:mobile_login,返回UserMobileLoginSerializerif self.action == 'mul_login':return UserMulLoginSerializer(data=data)else:return UserMobileLoginSerializer(data=data)def common_login(self, request):ser = self.get_serializer(data=request.data)ser.is_valid(raise_exception=True)token = ser.context.get('token')username = ser.context.get('username')icon = ser.context.get('icon')return APIResponse(token=token, username=username, icon=icon)@action(methods=['GET'], detail=False)def send_sms(self, request):mobile = request.query_params.get('mobile')if re.match(r'^1[3-9]\d{9}$', mobile): # 通过正则校验手机号code = get_code() # 获取随机验证码cache.set(f'sms_code_{mobile}', code) # 保存验证码到内存中res = send_sms_by_phone(mobile, code)if res:return APIResponse(msg='发送短信成功')else:# raise APIException('发送短信失败')return APIResponse(msg='发送短信失败', code=101)else:return APIResponse(msg='手机号不合法', code=102)@action(methods=['GET'], detail=False)def mobile(self, request):try:mobile = request.query_params.get('mobile')UserInfo.objects.get(mobile=mobile)return APIResponse(msg='手机号存在')except Exception as e:raise APIException('手机号不存在')"""多用户登录与手机号登录内部代码只有序列化类不同,抽取成一个方法"""@action(methods=['POST'], detail=False)def mul_login(self, request):return self.common_login(request)@action(methods=['POST'], detail=False)def mobile_login(self, request):return self.common_login(request)
# 多个序列化类使用了相同的代码,抽取出一个父类
class ModelUserSerializer(serializers.ModelSerializer):def _get_token(self, user):try:payload = jwt_payload_handler(user)token = jwt_encode_handler(payload)return tokenexcept Exception as e:raise APIException(str(e))def validate(self, attrs):# 1 手机号和codeuser = self._get_user(attrs)# 2 签发tokentoken = self._get_token(user)# 3 把token放到序列化类对象中self.context['token'] = tokenself.context['username'] = user.usernameself.context['icon'] = 'http://127.0.0.1:8000/media/' + str(user.icon)return attrsclass UserMulLoginSerializer(ModelUserSerializer):username = serializers.CharField()class Meta:model = UserInfofields = ['username', 'password']def _get_user(self, attrs):# attrs是校验后的数据:通过了字段自己的校验和局部钩子才会执行到这里username = attrs.get('username')password = attrs.get('password')# username是手机号/邮箱/用户名其中之一,我们使用正则判断if re.match(r'^1[3-9]\d{9}$', username):user = authenticate(mobile=username, password=password)elif re.match(r'^.+@.+\..+$', username):user = authenticate(email=username, password=password)else:user = authenticate(username=username, password=password)if user:return userelse:raise ValidationError('用户名或密码错误')class UserMobileLoginSerializer(ModelUserSerializer):code = serializers.CharField()mobile = serializers.CharField()class Meta:model = UserInfofields = ['mobile', 'code']def _get_user(self, attrs):mobile = attrs.get('mobile')code = attrs.get('code')# 校验code是否正确old_code = cache.get('sms_code_%s' % mobile)cache.set('sms_code_%s' % mobile, '') # 验证码用过了要清除if code == old_code: # 万能验证码,在测试阶段,测试用的user = UserInfo.objects.filter(mobile=mobile).first()return userraise APIException('验证码错误')