您好,登錄后才能下訂單哦!
這篇文章主要講解了“vue怎么實(shí)現(xiàn)短信驗(yàn)證碼”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“vue怎么實(shí)現(xiàn)短信驗(yàn)證碼”吧!
我們?cè)谧鼍W(wǎng)站開(kāi)發(fā)時(shí),登錄頁(yè)面很多情況下是可以用手機(jī)號(hào)接收短信驗(yàn)證碼,然后實(shí)現(xiàn)登錄的,那我們今天就來(lái)做一做這一功能。
偽代碼:
進(jìn)入登錄頁(yè)面,點(diǎn)擊短信登錄
輸入手機(jī)號(hào)碼,點(diǎn)擊獲取驗(yàn)證碼,后端在redis里保存驗(yàn)證碼
用戶(hù)把手機(jī)收到的驗(yàn)證碼輸入,點(diǎn)擊登錄,會(huì)把手機(jī)號(hào)和驗(yàn)證碼發(fā)往后端,然后進(jìn)行驗(yàn)證
要想發(fā)送短信,讓用戶(hù)收到短信,我們的借助一個(gè)容聯(lián)云的接口,注冊(cè)一個(gè)賬號(hào)。
使用時(shí)需要的一些參數(shù):
下載sdk
1.。。。。。。。
2.。。。。。。
3.。。。。。。。
下載完成后,解壓。放入我們drf項(xiàng)目的apps里的libs里
2,配置sms.py文件
# -*- coding:utf-8 -*- from .CCPRestSDK import REST # 說(shuō)明:主賬號(hào),登陸云通訊網(wǎng)站后,可在"控制臺(tái)-應(yīng)用"中看到開(kāi)發(fā)者主賬號(hào)ACCOUNT SID _accountSid = "xxxxxxxxxxxxx" # 8a216da863f8e6c20164139687e80c1b # 說(shuō)明:主賬號(hào)Token,登陸云通訊網(wǎng)站后,可在控制臺(tái)-應(yīng)用中看到開(kāi)發(fā)者主賬號(hào)AUTH TOKEN _accountToken = "xxxxxxxxxxxxx" # 6dd01b2b60104b3dbc88b2b74158bac6 # 請(qǐng)使用管理控制臺(tái)首頁(yè)的APPID或自己創(chuàng)建應(yīng)用的APPID _appId = "8aaf0708697b6beb01699f3c645f1766" # 8a216da863f8e6c20164139688400c21 # 說(shuō)明:請(qǐng)求地址,生產(chǎn)環(huán)境配置成app.cloopen.com _serverIP = "sandboxapp.cloopen.com" # 說(shuō)明:請(qǐng)求端口 ,生產(chǎn)環(huán)境為8883 _serverPort = "8883" # 說(shuō)明:REST API版本號(hào)保持不變 _softVersion = "2013-12-26" #下面的內(nèi)容不用修改 class CCP(object): """發(fā)送短信的輔助類(lèi)""" def __new__(cls, *args, **kwargs): # 判斷是否存在類(lèi)屬性_instance,_instance是類(lèi)CCP的唯一對(duì)象,即單例 if not hasattr(CCP, "_instance"): cls._instance = super(CCP, cls).__new__(cls, *args, **kwargs) cls._instance.rest = REST(_serverIP, _serverPort, _softVersion) cls._instance.rest.setAccount(_accountSid, _accountToken) cls._instance.rest.setAppId(_appId) return cls._instance def send_template_sms(self, to, datas, temp_id): """發(fā)送模板短信""" # @param to 手機(jī)號(hào)碼 # @param datas 內(nèi)容數(shù)據(jù) 格式為數(shù)組 例如:{"12","34"},如不需替換請(qǐng)?zhí)?nbsp;"" # @param temp_id 模板Id result = self.rest.sendTemplateSMS(to, datas, temp_id) # 如果云通訊發(fā)送短信成功,返回的字典數(shù)據(jù)result中statuCode字段的值為"000000" if result.get("statusCode") == "000000": # 返回0 表示發(fā)送短信成功 return 0 else: # 返回-1 表示發(fā)送失敗 return -1 if __name__ == "__main__": ccp = CCP() # 注意: 測(cè)試的短信模板編號(hào)為1 ccp.send_template_sms("15914397060", ["1234", 5], 1)
views.py,這是獲取驗(yàn)證碼請(qǐng)求的處理,也就是后端產(chǎn)生一個(gè)隨機(jī)碼,發(fā)送給手機(jī)用戶(hù),然后把隨機(jī)碼存儲(chǔ)于redis中,然后給前端返回一個(gè)驗(yàn)證碼發(fā)送成功的信號(hào)
from .models import User from rest_framework import status from lufei_drf.libs.yuntongxun.sms import CCP from django_redis import get_redis_connection class SMSCodeAPIView(APIView): def get(self,request): # 1. 通過(guò)查詢(xún)字符串獲取手機(jī)號(hào)碼 phone = request.query_params.get("phone") ty=request.query_params.get("type") # 2. 發(fā)送短信之前驗(yàn)證碼驗(yàn)證一下手機(jī)號(hào)碼 if ty=="register": try: User.objects.get(phone=phone) return Response({"message": "當(dāng)前手機(jī)號(hào)已經(jīng)被注冊(cè)過(guò)"}, status=status.HTTP_400_BAD_REQUEST) except: pass redis = get_redis_connection("sms_code") if redis.get("times_%s" % phone): return Response({"message": "當(dāng)前手機(jī)號(hào)已經(jīng)在一分鐘內(nèi)發(fā)送過(guò)短信"}, status=status.HTTP_400_BAD_REQUEST) # 3. 使用手機(jī)號(hào)碼發(fā)送短信驗(yàn)證碼 # 生成一個(gè)短信驗(yàn)證碼 sms_code = "%04d" % random.randint(0, 9999) ccp = CCP() result = ccp.send_template_sms(phone,[sms_code,"5分鐘"],1) if result == 0: # 發(fā)送短信成功,保存短信驗(yàn)證碼到redis數(shù)據(jù)庫(kù)中 # 開(kāi)啟管道操作 pl = redis.pipeline() pl.multi() # 接下來(lái)會(huì)在管道中執(zhí)行多條命令 # setex(變量名,有效期[秒],值 ) SMS_EXPIRE_TIME = 5 * 60 # 短信驗(yàn)證碼的有效期 SMS_TIMES = 60 # 短信發(fā)送的間隔時(shí)間 # 把原來(lái)立即執(zhí)行的命令放置到管道 pl.setex("sms_%s" % phone, SMS_EXPIRE_TIME, sms_code) pl.setex("times_%s" % phone, SMS_TIMES, 1) # 統(tǒng)一執(zhí)行管道中的命令 pl.execute() # 4. 響應(yīng)數(shù)據(jù)給客戶(hù)端 return Response({"message":result},status=status.HTTP_200_OK)
urls.py
from django.urls import path # jwt內(nèi)部實(shí)現(xiàn)的登陸視圖 from rest_framework_jwt.views import obtain_jwt_token from .views import SMSCodeAPIView, urlpatterns=[ path(r"login/", obtain_jwt_token ), path("sms/",SMSCodeAPIView.as_view()), ]
utils.py,這是對(duì)用戶(hù)提交手機(jī)驗(yàn)證碼后,對(duì)手機(jī)號(hào)和驗(yàn)證碼的校對(duì)。判斷都正確后,返回一個(gè)對(duì)象,包括token,user信息等,
from django.contrib.auth.backends import ModelBackend from django_redis import get_redis_connection def jwt_response_payload_handler(token, user=None, request=None): """ 自定義jwt認(rèn)證成功返回?cái)?shù)據(jù) :token 返回的jwt :user 當(dāng)前登錄的用戶(hù)信息[對(duì)象] :request 當(dāng)前本次客戶(hù)端提交過(guò)來(lái)的數(shù)據(jù) """ return { "token": token, "id": user.id, "username": user.username, } #實(shí)現(xiàn)多功能登錄 import re from .models import User#查找用戶(hù)名或手機(jī)號(hào)是否已經(jīng)是我們的用戶(hù) def get_user_by_account(account): """ 根據(jù)帳號(hào)獲取user對(duì)象 :param account: 賬號(hào),可以是用戶(hù)名,也可以是手機(jī)號(hào) :return: User對(duì)象 或者 None """ try: if re.match("^1[3-9]d{9}$", account): # 帳號(hào)為手機(jī)號(hào) user = User.objects.get(phone=account) else: # 帳號(hào)為用戶(hù)名 user = User.objects.get(username=account) except User.DoesNotExist: return None else: return user #驗(yàn)證用戶(hù)提交的短信和我們保存在redis里的信息是否一致 def sms_code_verify(phone,sms_code): redis = get_redis_connection("sms_code") value=redis.get("sms_%s"%phone).decode() if value==sms_code: return True return False class UsernameMobileAuthBackend(ModelBackend): """ 自定義用戶(hù)名或手機(jī)號(hào)認(rèn)證 """ def authenticate(self, request, username=None, password=None, **kwargs): user = get_user_by_account(username) #當(dāng)密碼長(zhǎng)度為4時(shí),我判斷其為手機(jī)號(hào)和短信驗(yàn)證碼登錄 if len(password)==4 and user is not None and sms_code_verify(username,password): return user elif user is not None and user.check_password(password): return user else: return None
login組件
<template> <div id="login"> <div class="box"> <p> <img src="../../assets/login_title.png" alt=""> </p> <p class="sign">幫助有志向的年輕人通過(guò)努力學(xué)習(xí)獲得體面的工作和生活!</p> <div class="pass" v-show="num==1"> <div class="title2 cursor"> <span @click="num=1" :class="num==1 ? "show" :""">密碼登錄</span> <span @click="num=2" :class="num==2 ? "show" :""">短信登錄</span> </div> <input v-model="username" type="text" class="ss" placeholder="用戶(hù)名 / 手機(jī)號(hào)碼"> <input v-model="password" type="password" class="ss" placeholder="密碼"> <div id="captcha" class="ss"></div> <div class="t1"> <div class="left"> <input type="checkbox" class="cursor" v-model="remenber"> <div class="remenber cursor" >記住密碼</div> </div> <div class="right cursor">忘記密碼</div> </div> <button class="login_btn" @click="login1">登錄</button> <div class="register"> 沒(méi)有賬號(hào) <span><router-link to="/register">立即注冊(cè)</router-link></span> </div> </div> <div class="messge" v-show="num==2"> <div class="title2 cursor"> <span @click="num=1" :class="num==1 ? "show" :""">密碼登錄</span> <span @click="num=2" :class="num==2 ? "show" :""">短信登錄</span> </div> <input v-model="phone" type="text" class="ss" placeholder="手機(jī)號(hào)碼"> <div class="sms"> <input v-model="sms_code" type="text" class="ss"> <div class="content" @click="get_sms_code">{{content}}</div> </div> <button class="login_btn" @click="sms_login">登錄</button> <div class="register"> 沒(méi)有賬號(hào) <span><router-link to="/register">立即注冊(cè)</router-link></span> </div> </div> </div> </div> </template> <script> export default { name:"login", data:function () { return { num:1, username:"", password:"", remenber:"", status:"", content:"獲取驗(yàn)證碼", phone:"", sms_code:"", } }, methods:{ //手機(jī)號(hào)和短信驗(yàn)證碼登錄 sms_login:function(){ let _this=this; this.$axios.post("http://127.0.0.1:8000/user/login/",{ "username":_this.phone, "password":_this.sms_code, },{responseType:"json"}) .then(function (res) { sessionStorage.token=res.data.token; _this.$router.go(-1); }).catch(function (error) { console.log(error.response) }); }, //獲取短信驗(yàn)證碼 get_sms_code:function(){ let reg = /1[3-9]{2}d{8}/; if( reg.test(this.phone) ){ if(this.content == "獲取驗(yàn)證碼"){ this.content=60; let _this=this; let tt=setInterval(function () { if (_this.content>=1){ _this.content-- } else { _this.content="獲取驗(yàn)證碼"; clearInterval(tt) } },1000); this.$axios.get("http://127.0.0.1:8000/user/sms?type=login&phone="+this.phone) .then(function (res) { if(res.data.message==0){ alert("驗(yàn)證碼發(fā)送成功") } }).catch(function (error) { console.log(error.response) }) } }else { alert("手機(jī)號(hào)碼有誤") } }, //用戶(hù)名和密碼登錄 login1:function () { if (this.status==1){ let _this=this; this.$axios.post("http://127.0.0.1:8000/user/login/",{ "username":_this.username, "password":_this.password, },{responseType:"json"}) .then(function (res) { if (res.status==200){ if (_this.remenber){ sessionStorage.removeItem("token"); localStorage.token=res.data.token; } else { localStorage.removeItem("token"); sessionStorage.token=res.data.token } _this.$router.go(-1); } else { alert("用戶(hù)名或密碼錯(cuò)誤") } }) .catch(function (error) { alert(error.response.data.non_field_errors[0]); console.log(error.response.data.non_field_errors); }); } else { alert("驗(yàn)證碼錯(cuò)誤") } }, handlerPopup:function (captchaObj) { let _this=this; captchaObj.onSuccess(function () { var validate = captchaObj.getValidate(); _this.$axios.post("http://127.0.0.1:8000/user/yzm/",{ geetest_challenge: validate.geetest_challenge, geetest_validate: validate.geetest_validate, geetest_seccode: validate.geetest_seccode, },{ responseType:"json", }).then(function (res) { _this.status=res.data.status }).catch(function (error) { console.log(error) }) }); captchaObj.appendTo("#captcha"); } }, created:function () { let _this=this; this.$axios.get("http://127.0.0.1:8000/user/yzm") .then(function (res) { let data=JSON.parse(res.data); initGeetest({ width:"350px", gt: data.gt, challenge: data.challenge, product: "popup", offline: !data.success }, _this.handlerPopup); }).catch(function (error) { console.log(error) }) } } </script> <style scoped> #login{ background: url("../../assets/Login.jpg"); background-size: 100% 100%; height: 100%; position: fixed; width: 100%; } .box{ width: 500px; height: 600px; margin: 0 auto; margin-top: 200px; text-align: center; } .box img{ width: 190px; height: auto; } .box p{ margin: 0; } .sign{ font-size: 18px; color: #fff; letter-spacing: .29px; padding-top: 10px; padding-bottom: 50px; } .pass{ width: 400px; height: 460px; margin: 0 auto; background-color: white; border-radius: 4px; } .messge{ width: 400px; height: 390px; margin: 0 auto; background-color: white; border-radius: 4px; } .title2{ width: 350px; font-size: 20px; color: #9b9b9b; padding-top: 50px; border-bottom: 1px solid #e6e6e6; margin: 0 auto; margin-bottom: 20px; } .ss{ width: 350px; height: 45px; border-radius: 4px; border: 1px solid #d9d9d9; text-indent: 20px; font-size: 14px; margin-bottom: 20px; } .pass .t1{ width: 350px; margin: 0 auto; height: 20px; line-height: 20px; font-size: 12px; text-align: center; position: relative; } .t1 .right{ position: absolute; right: 0; } .remenber{ display: inline-block; position: absolute; left: 20px; } .left input{ position: absolute; left:0; width: 14px; height: 14px; } .login_btn{ width: 350px; height: 45px; background: #ffc210; border-radius: 5px; font-size: 16px; color: #fff; letter-spacing: .26px; margin-top: 30px; outline: none; border:none; cursor: pointer; } .register{ margin-top: 20px; font-size: 14px; color: #9b9b9b; } .register span{ color: #ffc210; cursor: pointer; } .cursor{ cursor: pointer; } .show{ display: inline-block; padding-bottom: 5px; border-bottom: 2px solid orange; color: #4a4a4a; } a{ text-decoration: none; color: #ffc210; } #captcha{ margin: 0 auto; height: 44px; } .sms{ position: relative; width: 350px; height: 45px; margin: 0 auto; line-height: 45px; } .sms .content{ position: absolute; top:0; right: 10px; color: orange; border-left: 1px solid orange; padding-left: 10px; cursor: pointer; } </style>
前端獲取短信驗(yàn)證碼:
//獲取短信驗(yàn)證碼 get_sms_code:function(){ let reg = /1[3-9]{2}d{8}/; //當(dāng)手機(jī)號(hào)為為真實(shí)手機(jī)號(hào),才可以觸發(fā)獲取驗(yàn)證碼 if( reg.test(this.phone) ){ //當(dāng)頁(yè)面上顯示為‘獲取驗(yàn)證碼"時(shí),才可以觸發(fā)獲取驗(yàn)證碼請(qǐng)求;當(dāng)進(jìn)入倒計(jì)時(shí),點(diǎn)擊不能觸發(fā)獲取驗(yàn)證碼請(qǐng)求 if(this.content == "獲取驗(yàn)證碼"){ //成功發(fā)送獲取驗(yàn)證碼請(qǐng)求之后開(kāi)始倒計(jì)時(shí)60秒 this.content=60; let _this=this; let tt=setInterval(function () { if (_this.content>=1){ _this.content-- } else { _this.content="獲取驗(yàn)證碼"; clearInterval(tt) } },1000); this.$axios.get("http://127.0.0.1:8000/user/sms?type=login&phone="+this.phone) .then(function (res) { if(res.data.message==0){ alert("驗(yàn)證碼發(fā)送成功") } }).catch(function (error) { console.log(error.response) }) } }else { alert("手機(jī)號(hào)碼有誤") } },
前端用手機(jī)號(hào)和短信驗(yàn)證碼登錄:
//獲取短信驗(yàn)證碼 get_sms_code:function(){ let reg = /1[3-9]{2}d{8}/; //當(dāng)手機(jī)號(hào)為為真實(shí)手機(jī)號(hào),才可以觸發(fā)獲取驗(yàn)證碼 if( reg.test(this.phone) ){ //當(dāng)頁(yè)面上顯示為‘獲取驗(yàn)證碼"時(shí),才可以觸發(fā)獲取驗(yàn)證碼請(qǐng)求;當(dāng)進(jìn)入倒計(jì)時(shí),點(diǎn)擊不能觸發(fā)獲取驗(yàn)證碼請(qǐng)求 if(this.content == "獲取驗(yàn)證碼"){ //成功發(fā)送獲取驗(yàn)證碼請(qǐng)求之后開(kāi)始倒計(jì)時(shí)60秒 this.content=60; let _this=this; let tt=setInterval(function () { if (_this.content>=1){ _this.content-- } else { _this.content="獲取驗(yàn)證碼"; clearInterval(tt) } },1000); this.$axios.get("http://127.0.0.1:8000/user/sms?type=login&phone="+this.phone) .then(function (res) { if(res.data.message==0){ alert("驗(yàn)證碼發(fā)送成功") } }).catch(function (error) { console.log(error.response) }) } }else { alert("手機(jī)號(hào)碼有誤") } },
感謝各位的閱讀,以上就是“vue怎么實(shí)現(xiàn)短信驗(yàn)證碼”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)vue怎么實(shí)現(xiàn)短信驗(yàn)證碼這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。