前后端分離情況下的圖形驗證碼

圖形驗證碼包含兩部分:圖片和文字驗證碼碍讯。在JSP時代淆两,圖形驗證碼生成和驗證是通過Session機制來實現(xiàn)的:后端生成圖片和文字驗證碼锯玛,并將文字驗證碼放在session中网棍,前端填寫驗證碼后提交到后臺,通過與session中的驗證碼比較來實現(xiàn)驗證历等。
在前后端分離的項目中讨惩,登錄使用的是Token驗證,而不是Session寒屯。后臺必須保證當前用戶輸入的驗證碼是用戶開始請求頁面時候的驗證碼荐捻,必須保證驗證碼的唯一性。
那么怎樣來實現(xiàn)呢寡夹,思路就是:
為每個驗證碼code分配一個主鍵codeId处面。前端請求驗證碼code時,將codeId在前端生成并發(fā)送給后端菩掏;后端生成code及圖形驗證碼后魂角,并與codeId關(guān)聯(lián)保存;前端填寫好code后智绸,將code和codeId一并提交到后端野揪,后端對code和codeId進行比較,完成驗證传于。

下面貼上代碼囱挑。

1、前端請求驗證碼

<div class="captcha-img">
         <input type="hidden" name="r" id="r" value="">
         <img id="captchaPic" src="#" onclick="getVerifiCode()">
</div>

//生成圖片驗證碼
function getVerifiCode() {
        var r = Math.random();//codeId沼溜,隨機數(shù)
        $("#r").val(r);
        $("#captchaPic").prop('src',commonObj.hostUrl + '/imgCode?r=' + r);
 }

在頁面放了一個隱藏input用來保存codeId平挑,請求時將codeId帶上

2、后端生成驗證碼


    //生成驗證碼
    @GetMapping("/imgCode")
    public void creaeCode(HttpServletRequest request, HttpServletResponse response){
        ImageCode imagecode=new ImageCode();//圖形驗證碼工具類
        BufferedImage img=imagecode.getImage();
        try {
            String codeId = request.getParameter("r");//從前端傳codeId
            String code = imagecode.getValidateCode();//驗證碼
            service.saveImgCode(codeId, code);//后端保存驗證碼code和codeId
            response.setContentType("image/jpeg");
            imagecode.saveImage(img, response.getOutputStream());
        } catch (IOException e) {
            logger.error("生成圖片驗證碼異常", e);
        }
    }

附上圖形驗證碼生成類


public class ImageCode {
    int w=79;//寬度
    int h=30;//高度

    private String validateCode = "";//驗證碼

    Random r=new Random();

    public  BufferedImage CreateImage(){//生成圖片的方法
        BufferedImage img=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);//內(nèi)存中創(chuàng)建一張圖片
        Graphics gps=img.getGraphics();//獲取當前圖片的畫筆

        gps.setColor(new Color(240,240,240));//設(shè)置畫筆

        gps.fillRect(0, 0, w, h);//填充一個與圖片一樣大小的矩形(其實就是為了設(shè)置背景顏色)
        return img;


    }
    public  BufferedImage getImage(){//得到圖片的方法
        BufferedImage img=CreateImage();
        Graphics gps=img.getGraphics();//獲取當前圖片的畫筆
        StringBuilder sb = new StringBuilder();
        //開始畫東西
        for(int i=0;i<4;i++){
            String ch=this.getContent();
            sb.append(ch);
            gps.setColor(this.getColor());
            gps.setFont(this.getFont());
            gps.drawString(ch, w/4*i, h-5);//寬度讓其不滿圖片
        }
        drawLine(img);
        validateCode = sb.toString();
        return img;

    }
    public  void saveImage(BufferedImage img,OutputStream out) throws  IOException {
        //這里為了測試將生成的圖片放入f盤,在實際的項目開發(fā)中是需要將生成的圖片寫入客戶端的:
        ImageIO.write(img, "JPEG", out);//response.getOutputStream()

        //ImageIO.write(img, "JPEG", new FileOutputStream("F:\\a.jpg"));//保存到硬盤

    }
    //在圖片中插入字母和十個數(shù)字
    String str="abcdefghijklmnupqrstuvwxyzABCDEFGHIJKLMNUPQRSTUVWZYZ1234567890";
    public   String getContent(){
        int index=r.nextInt(str.length());
        return str.charAt(index)+"";
    }
    String[] font={"宋體","華文楷體","華文隸書","黑體","華文新魏"};//字體
    int[] fontSize={24,25,26,27,28};//字號大小
    int[] fontStyle={0,1,2,3};//字體樣式
    public   Font getFont(){
        int index1=r.nextInt(font.length);
        String name=font[index1];
        int style=r.nextInt(4);
        int index2=r.nextInt(fontSize.length);
        int size=fontSize[index2];
        return new Font(name,style,size);
    }
    public   Color getColor(){//得到不同的顏色
        int R=r.nextInt(256);//取值范圍是0-255
        int G=r.nextInt(256);
        int B=r.nextInt(256);
        return new Color(R,G,B);
    }
    public void drawLine(BufferedImage img){//畫干擾線
        Graphics2D gs=(Graphics2D) img.getGraphics();
        gs.setColor(Color.BLACK);
        gs.setStroke(new BasicStroke(1.0F));//設(shè)置線的寬度
        for(int i=0;i<5;i++){//橫坐標不能超過寬度通熄,縱坐標不能超過高度
            int x1=r.nextInt(w);
            int y1=r.nextInt(h);
            int x2=r.nextInt(w);
            int y2=r.nextInt(h);
            gs.drawLine(x1, y1, x2, y2);

        }
    }

    public String getValidateCode(){
        return this.validateCode;
    }
}

3唆涝、登陸時提交驗證碼
登錄界面:

image.png

提交登錄代碼:

            //執(zhí)行登錄
            var regData = {
                accName:data.username,
                accPwd:hex_md5(data.password),
                code:data.captcha,
                codeId:$("#r").val()
            };
            //提交數(shù)據(jù)到后臺
            commonObj.ajaxData("/api/account/login", "post", JSON.stringify(regData), function     (res) {
                //登錄成功
                var data = res.data;
                window.location.href='index.html';
            });

4、后臺校驗驗證碼

public Object doLogin(Map<String, Object> data) throws Exception {

        String accName = (String) data.get("accName");
        String accPwd = (String) data.get("accPwd");
        String code = (String) data.get("code");//驗證碼
        String codeId = (String) data.get("codeId");//驗證碼id

        Assert.hasText(accName, "賬戶名不能為空");
        Assert.hasText(accPwd, "密碼不能為空");

        //驗證碼驗證
        Assert.hasText(codeId, "驗證碼錯誤");
        PhoneCode phoneCode = codeService.validImgCode(codeId, code);
        ...
        //執(zhí)行登錄過程
        //todo
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唇辨,一起剝皮案震驚了整個濱河市廊酣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赏枚,老刑警劉巖亡驰,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異饿幅,居然都是意外死亡凡辱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門栗恩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來透乾,“玉大人,你說我怎么就攤上這事磕秤∪槲冢” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵市咆,是天一觀的道長汉操。 經(jīng)常有香客問我,道長床绪,這世上最難降的妖魔是什么客情? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任其弊,我火速辦了婚禮癞己,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梭伐。我一直安慰自己痹雅,他們只是感情好,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布糊识。 她就那樣靜靜地躺著绩社,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赂苗。 梳的紋絲不亂的頭發(fā)上愉耙,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音拌滋,去河邊找鬼朴沿。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的赌渣。 我是一名探鬼主播魏铅,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坚芜!你這毒婦竟也來了览芳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤鸿竖,失蹤者是張志新(化名)和其女友劉穎沧竟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缚忧,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡屯仗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了搔谴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魁袜。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖敦第,靈堂內(nèi)的尸體忽然破棺而出峰弹,到底是詐尸還是另有隱情,我是刑警寧澤芜果,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布鞠呈,位于F島的核電站,受9級特大地震影響右钾,放射性物質(zhì)發(fā)生泄漏蚁吝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一舀射、第九天 我趴在偏房一處隱蔽的房頂上張望窘茁。 院中可真熱鬧,春花似錦脆烟、人聲如沸山林。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驼抹。三九已至,卻和暖如春拜鹤,著一層夾襖步出監(jiān)牢的瞬間框冀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工敏簿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留明也,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像诡右,于是被迫代替她去往敵國和親安岂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容