程序員不裝x能行?先給登陸來一個圖形驗證碼!(canvas實現)

細心的同窗能夠發現,如今不少網站當登陸屢次以後就會出現一個圖形驗證碼,或是當提交表單、或點擊獲取手機驗證碼等等場景都會有圖形驗證碼的出現。javascript

那麼圖形驗證碼是爲了解決什麼問題而出現的呢?html

什麼是圖形驗證碼

圖形驗證碼是驗證碼的一種。驗證碼(CAPTCHA)是「Completely Automated Public Turing test to tell Computers and Humans Apart」(全自動區分計算機和人類的圖靈測試)的縮寫,是一種區分用戶是計算機仍是人的公共全自動程序。能夠防止:惡意破解密碼、刷票、論壇灌水,有效防止某個黑客對某一個特定註冊用戶用特定程序暴力破解方式進行不斷的登錄嘗試,實際上用驗證碼是如今不少網站通行的方式。前端

既然圖形驗證碼是爲了區分機器和人之間的操做,那麼咱們就能夠在圖形上繪製一個只有人能夠解答的問題。比較常見的是在圖片上生成文字驗證碼,而後用戶輸入圖片上的文字吻合則驗證經過。java

雖然這種驗證方法已經漸漸的被其餘更先進的方法所淘汰了(圖片上的文字依然能夠被程序識別讀取),而且前端生成驗證碼的方式相較於後端安全性不高,但咱們的目的只是爲了裝x,提高程序的安全性只是附帶的效果。ios

登陸表單

首先咱們須要在在登陸表單上額外添加用於輸入驗證碼的FormItem,而且給圖形驗證碼提供一個canvas容器。有時候生成的驗證碼看不明白,所以須要給驗證碼添加點擊事件用以切換驗證碼:canvas

<Form ref="loginForm" :model="form" :rules="rules">
    <FormItem prop="userName">
        <Input v-model="form.userName" placeholder="請輸入用戶名">
            <span slot="prepend">
                <Icon :size="16" type="person"></Icon>
            </span>
        </Input>
    </FormItem>
    <FormItem prop="password">
        <Input type="password" v-model="form.password" placeholder="請輸入密碼">
            <span slot="prepend">
                <Icon :size="14" type="locked"></Icon>
            </span>
        </Input>
    </FormItem>
    <FormItem prop="valiCode" v-show="this.count">
        <Input v-model="form.valiCode" placeholder="請輸入驗證碼">
            <span slot="prepend">
                <Icon :size="14" type="ios-analytics"></Icon>
            </span>
        </Input>
        <div class="canvas" @click="getImgYanzheng">
            <canvas id="canvas"></canvas>
        </div>
    </FormItem>
    <FormItem>
        <Button @click="handleSubmit" type="primary" long>登陸</Button>
    </FormItem>
</Form>

須要用到的屬性

表單須要額外添加valiCode用以記錄用戶輸入的驗證碼。此處咱們定義當用戶登陸失敗一次則須要額外輸入圖形驗證碼,所以添加count屬性,當登錄失敗時count++,固然這樣的處理方式並非很嚴謹,而且用戶刷新頁面count則會清零。能夠在此處能夠增長更多限制,如異地登陸等,因爲本案例徹底沒有涉及到後端程序,所以只是簡單的以count爲判斷依據。後端

data() {
    return {
      form: {
        userName: "",// 用戶名
        password: "",// 密碼
        valiCode: ""// 驗證碼
      },
      count: 0, // 登陸次數
      show_num: [],// 圖形上的文字
    }
}

生產圖形驗證碼

頁面上爲canvas容器綁定的方法getImgYanzheng就是在繪製圖形驗證碼數組

。在繪製圖形驗證碼時須要爲你的驗證碼定義一個內容集合,此處使用的是:A,B,C,E,F,G,H,J,K,M,N,P,Q,R,S,T,W,X,Y,Z,1,2,3,4,5,6,7,8,9,0,好,醫,生。字母中剔除了容易誤識別的幾個字母而且能夠隨意加入文字(所以圖形驗證碼也可在作成隨機生成四個文字讓用戶點擊,或者生成成語讓用戶填空等等各類形式)。而且忽略用戶大小寫,所以須要用到toLowerCase方法。安全

接下來就是canvas繪圖的一些技巧了。dom

canvas繪圖

canvas 元素自己是沒有繪圖能力的。全部的繪製工做必須在 JavaScript 內部完成:

var c=document.getElementById("myCanvas");
var cxt=c.getContext("2d");

在JavaScript 中使用 id 來尋找 canvas 元素,而後建立context對象,getContext("2d")對象是內建的 HTML5 對象,擁有多種繪製路徑、矩形、圓形、字符以及添加圖像的方法。咱們能夠把canvas 想象成景色而context則是景色呈現的畫布。

因爲繪製驗證碼的過程當中是從左往右繪製的,所以須要規劃好畫布的使用範圍,另外在驗證碼繪製時還要加上一些隨機的元素使驗證碼不容易被程序識別。

getImgYanzheng() {
      var show_num = [];
      var canvas_width = 150; //document.getElementById("canvas").style.width;
      var canvas_height = 30; //document.getElementById("canvas").style.height;
      var canvas = document.getElementById("canvas"); //獲取到canvas的對象,景色
      var context = canvas.getContext("2d"); //獲取到canvas畫圖的環境,景色呈現的畫布
      canvas.width = canvas_width;
      canvas.height = canvas_height;
      var sCode =
        "A,B,C,E,F,G,H,J,K,M,N,P,Q,R,S,T,W,X,Y,Z,1,2,3,4,5,6,7,8,9,0,好,醫,生";
      var aCode = sCode.split(",");
      var aLength = aCode.length; //獲取到數組的長度

      for (var i = 0; i <= 3; i++) {
        var j = Math.floor(Math.random() * aLength); //獲取到隨機的索引值
        var deg = (Math.random() * 30 * Math.PI) / 180; //產生0~30之間的隨機弧度
        var txt = aCode[j]; //獲得隨機的一個內容
        show_num[i] = txt.toLowerCase();
        var x = 10 + i * 20; //文字在canvas上的x座標
        var y = 20 + Math.random() * 8; //文字在canvas上的y座標
        context.font = "bold 23px 微軟雅黑";

        context.translate(x, y);
        context.rotate(deg);

        context.fillStyle = this.randomColor();
        context.fillText(txt, 0, 0);

        context.rotate(-deg);
        context.translate(-x, -y);
      }
      for (var i = 0; i <= 5; i++) {
        //驗證碼上顯示線條
        context.strokeStyle = this.randomColor();
        context.beginPath();
        context.moveTo(
          Math.random() * canvas_width,
          Math.random() * canvas_height
        );
        context.lineTo(
          Math.random() * canvas_width,
          Math.random() * canvas_height
        );
        context.stroke();
      }
      for (var i = 0; i <= 30; i++) {
        //驗證碼上顯示小點
        context.strokeStyle = this.randomColor();
        context.beginPath();
        var x = Math.random() * canvas_width;
        var y = Math.random() * canvas_height;
        context.moveTo(x, y);
        context.lineTo(x + 1, y + 1);
        context.stroke();
      }
      this.show_num = show_num;
    },

驗證碼及線條須要一些隨機的顏色:

randomColor() {
      //獲得隨機的顏色值
      var r = Math.floor(Math.random() * 256);
      var g = Math.floor(Math.random() * 256);
      var b = Math.floor(Math.random() * 256);
      return "rgb(" + r + "," + g + "," + b + ")";
    }

有了以上兩個方法,圖形驗證碼就已經生成完畢了,接下來就是使用的問題了。

使用圖形驗證碼

判斷登陸次數count,若是登陸次數大於0則須要輸入驗證碼:

const self = this;
if (this.count) {
        if (this.form.valiCode) {
            if (this.show_num.join("") != this.form.valiCode.toLowerCase()) {
                self.$Notice.warning({
                    title: "驗證碼錯誤"
                });
                return;
            }
        } else {
            self.$Notice.warning({
                title: "請輸入驗證碼"
            });
            return;
        }
    }

當登陸失敗時須要執行count++而且刷新驗證碼:

self.count++;
self.getImgYanzheng();
self.$Notice.warning({
title: "登錄失敗",
desc: rs.data.msg
});

此時就完成了一個圖形驗證碼的添加工做,同窗們快裝起來吧。
file
轉評贊就是最大的鼓勵
關注公衆號,更多驚喜等着你

相關文章
相關標籤/搜索