前後端分離,SpringBoot如何實現驗證碼操作

来源:https://www.cnblogs.com/alanlin/archive/2022/05/16/16276914.html
-Advertisement-
Play Games

驗證碼的功能是防止非法用戶惡意去訪問登錄介面而設置的一個功能,今天我們就來看看在前後端分離的項目中,SpringBoot是如何提供服務的。 SpringBoot版本 本文基於的Spring Boot的版本是2.6.7 。 引入依賴 captcha一款超簡單的驗證碼生成,還挺好玩的.還有中文驗證碼,動 ...


驗證碼的功能是防止非法用戶惡意去訪問登錄介面而設置的一個功能,今天我們就來看看在前後端分離的項目中,SpringBoot是如何提供服務的。

SpringBoot版本

本文基於的Spring Boot的版本是2.6.7 。

引入依賴

captcha一款超簡單的驗證碼生成,還挺好玩的.還有中文驗證碼,動態驗證碼. 。在項目中pom.xml配置文件中添加依賴,如下:

<!--驗證碼-->
<dependency>
    <groupId>com.github.whvcse</groupId>
    <artifactId>easy-captcha</artifactId>
    <version>1.6.2</version>
</dependency>

實現思路

  • 把生成的驗證碼結果保存到redis緩存中,並設置過期時間。
  • 前端通過提交驗證碼和key,其中key就是保存到redis中的鍵,通過這個鍵獲取到對應的值,再與前端提交的值對比,相同就通過驗證。

實現過程

新建驗證碼枚舉類

由於captcha這款驗證碼提供了好幾種驗證碼方法,有中文驗證碼,動態驗證碼,算術驗證碼等等,新建一個驗證碼每周類存放這幾種驗證碼類型。代碼如下:

public enum LoginCodeEnum {
    /**
     * 算數
     */
    ARITHMETIC,
    /**
     * 中文
     */
    CHINESE,
    /**
     * 中文閃圖
     */
    CHINESE_GIF,
    /**
     * 閃圖
     */
    GIF,
    SPEC
}

定義驗證碼配置信息

該類是定義驗證碼的基本信息,例如高度、寬度、字體類型、驗證碼類型等等、並且我們把它轉成通過SpringBoot配置文件類型來定義更加方便。

@Data
public class LoginCode {

    /**
     * 驗證碼配置
     */
    private LoginCodeEnum codeType;
    /**
     * 驗證碼有效期 分鐘
     */
    private Long expiration = 2L;
    /**
     * 驗證碼內容長度
     */
    private int length = 2;
    /**
     * 驗證碼寬度
     */
    private int width = 111;
    /**
     * 驗證碼高度
     */
    private int height = 36;
    /**
     * 驗證碼字體
     */
    private String fontName;
    /**
     * 字體大小
     */
    private int fontSize = 25;

    /**
     * 驗證碼首碼
     * @return
     */
    private  String   codeKey;


    public LoginCodeEnum getCodeType() {
        return codeType;
    }
}

把配置文件轉換Pojo類的統一配置類

@Configuration
public class ConfigBeanConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "login")
    public LoginProperties loginProperties() {
        return new LoginProperties();
    }
}

定義驗證邏輯生成類

@Data
public class LoginProperties {

    private LoginCode loginCode;


    /**
     * 獲取驗證碼生產類
     * @return
     */
    public Captcha getCaptcha(){
        if(Objects.isNull(loginCode)){
            loginCode = new LoginCode();
            if(Objects.isNull(loginCode.getCodeType())){
                loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
            }

        }
        return switchCaptcha(loginCode);
    }

    /**
     * 依據配置信息生產驗證碼
     * @param loginCode
     * @return
     */
    private Captcha switchCaptcha(LoginCode loginCode){
        Captcha captcha = null;
        synchronized (this){
            switch (loginCode.getCodeType()){
                case ARITHMETIC:
                    captcha = new FixedArithmeticCaptcha(loginCode.getWidth(),loginCode.getHeight());
                    captcha.setLen(loginCode.getLength());
                    break;
                case CHINESE:
                    captcha = new ChineseCaptcha(loginCode.getWidth(),loginCode.getHeight());
                    captcha.setLen(loginCode.getLength());
                    break;
                case CHINESE_GIF:
                    captcha = new ChineseGifCaptcha(loginCode.getWidth(),loginCode.getHeight());
                    captcha.setLen(loginCode.getLength());
                    break;
                case GIF:
                    captcha = new GifCaptcha(loginCode.getWidth(),loginCode.getHeight());
                    captcha.setLen(loginCode.getLength());
                    break;
                case SPEC:
                    captcha = new SpecCaptcha(loginCode.getWidth(),loginCode.getHeight());
                    captcha.setLen(loginCode.getLength());
                default:
                    System.out.println("驗證碼配置信息錯誤!正確配置查看 LoginCodeEnum ");

            }
        }
        if(StringUtils.isNotBlank(loginCode.getFontName())){
            captcha.setFont(new Font(loginCode.getFontName(),Font.PLAIN,loginCode.getFontSize()));
        }
        return captcha;
    }

    static  class FixedArithmeticCaptcha extends ArithmeticCaptcha{
        public FixedArithmeticCaptcha(int width,int height){
            super(width,height);
        }

        @Override
        protected char[] alphas() {
            // 生成隨機數字和運算符
            int n1 = num(1, 10), n2 = num(1, 10);
            int opt = num(3);

            // 計算結果
            int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
            // 轉換為字元運算符
            char optChar = "+-x".charAt(opt);

            this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
            this.chars = String.valueOf(res);

            return chars.toCharArray();
        }
    }
}

在控制層上定義驗證碼生成介面

   @ApiOperation(value = "獲取驗證碼", notes = "獲取驗證碼")
    @GetMapping("/code")
    public Object getCode(){

        Captcha captcha = loginProperties.getCaptcha();
        String uuid = "code-key-"+IdUtil.simpleUUID();
        //當驗證碼類型為 arithmetic時且長度 >= 2 時,captcha.text()的結果有幾率為浮點型
        String captchaValue = captcha.text();
        if(captcha.getCharType()-1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")){
            captchaValue = captchaValue.split("\\.")[0];
        }
        // 保存
        redisUtils.set(uuid,captchaValue,loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
        // 驗證碼信息
        Map<String,Object> imgResult = new HashMap<String,Object>(2){{
            put("img",captcha.toBase64());
            put("uuid",uuid);
        }};
        return imgResult;

    }

效果體驗

在前端調用介面

<template>
<div class="login-code">
  <img :src="codeUrl" @click="getCode">
</div>
</template>
<script>
    methods: {
    getCode() {
      getCodeImg().then(res => {
        this.codeUrl = res.data.img
        this.loginForm.uuid = res.data.uuid
      })
    },
    }
    created() {
    // 獲取驗證碼
    this.getCode()
  },
 </script>

本文來自博客園,作者:北根娃,轉載請註明原文鏈接:https://www.cnblogs.com/alanlin/p/16276914.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Servlet就是一個介面我們需要寫一個類然後去實現Servlet,就可以被伺服器識別到。request是用來接受客戶端傳過來的參數,respone是用來響應客戶端的頁面。我們所用的容器是一個繼承的java容器tomcat。 ...
  • 前言 最近我小表妹迷上了玩連連看,玩了一個星期了還沒通關,真的是菜。 我實在是看不過去了,直接用python寫了個腳本代碼,一分鐘一把游戲。 快是快,就是聯網玩容易被罵,嘿嘿~ 但是,又不是我玩,有什麼關係呢~ 哈哈哈 😎 代碼 導入所需模塊 # -*- coding:utf-8 -*- impo ...
  • sort包簡介 官方文檔 Golang的sort包用來排序,二分查找等操作。本文主要介紹sort包里常用的函數,通過實例代碼來快速學會使用sort包 sort包內置函數 sort.Ints(x []int) ints := []int{1, 4, 3, 2} fmt.Printf("%v\n", i ...
  • 本文mybatis-spring-boot探討在springboot工程中mybatis相關對象的註冊與載入。 建議先瞭解mybatis在spring中的使用和springboot自動裝載機制,再看此文章。 傳送門:Mybatis源碼解讀-配置載入和Mapper的生成 問題 @MapperScan和 ...
  • 一個工作了7年的粉絲,遇到了一個Zookeeper的問題。 因為接觸過Zookeeper這個技術,不知道該怎麼回答。 我說一個工作了7年的程式員,沒有接觸過主流技術,這不正常。 於是我問了他工資以後,我理解了! 好吧,關於“Zookeeper中Watch機制的實現原理”,看看普通人和高手的回答。 普 ...
  • 作者:何甜甜在嗎 鏈接:https://juejin.cn/post/6916150628955717646 寫在前面 在介紹具體方案之前,首先先介紹一下常見的加密演算法。加密演算法可以分為三大類: 對稱加密演算法 非對稱加密演算法 Hash演算法 對稱加密演算法 加密和解密使用相同的密鑰。對稱加密演算法加密解密 ...
  • RocketMQ學習 1.基本概念 RocketMQ是阿裡巴巴團隊使用java語言開發的一款分散式消息中間件,是一款低延遲,高可用,擁有海量消息堆積能力和靈活拓展性的消息隊列。 rocketmq的官網:http://rocketmq.apache.org gitee倉庫:https://gitee. ...
  • 多線程筆記(四) 1. Atomic框架包 Atomic包里放著所以保證線程安全的原子類 大致分為7類 基本數據類型的原子操作類 引用類型的原子操作類 數組類型的原子操作類 修改屬性欄位的原子操作類 帶版本的引用類型的原子操作類 增強的基本數據類型的原子操作類 增強操作的公共輔助類 2. Count ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...