溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

發(fā)布時(shí)間:2022-10-13 11:29:35 來(lái)源:億速云 閱讀:508 作者:iii 欄目:開(kāi)發(fā)技術(shù)

今天小編給大家分享一下vue如何實(shí)現(xiàn)短信驗(yàn)證碼的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來(lái)了解一下吧。

一、需求

1,需求

  我們?cè)谧鼍W(wǎng)站開(kāi)發(fā)時(shí),登錄頁(yè)面很多情況下是可以用手機(jī)號(hào)接收短信驗(yàn)證碼,然后實(shí)現(xiàn)登錄的,那我們今天就來(lái)做一做這一功能。

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

偽代碼:

進(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)。

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

使用時(shí)需要的一些參數(shù):

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

下載sdk

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

下載完成后,解壓。放入我們drf項(xiàng)目的apps里的libs里

二、sdk參數(shù)配置  

1,目錄結(jié)構(gòu)

vue如何實(shí)現(xiàn)短信驗(yàn)證碼

  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)

三、代碼實(shí)現(xiàn)

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

2,前端代碼

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)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guā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)容。

vue
AI