天天看點

內建nanocaptcha庫生成登入驗證碼背景步驟測試總結參考:

背景

需要實作一個驗證碼登入的功能需求。這個需求挺簡單的,主要實作驗證碼圖檔生成給前端,然後,在登入接口比對驗證碼即可。剛拿到這個需求,好久沒有搞過登入這一塊了,是以,查了一下相關驗證碼的知識。下面是維基百科中關于驗證碼的說明:

全自動區分計算機和人類的圖靈測試(英語:Completely Automated Public Turing test to tell Computers and Humans Apart,簡稱CAPTCHA),又稱驗證碼,是一種區分使用者是機器或人類的公共全自動程式。在CAPTCHA測試中,作為伺服器的計算機會自動生成一個問題由使用者來解答。這個問題可以由計算機生成并評判,但是必須隻有人類才能解答。由于機器無法解答CAPTCHA的問題,回答出問題的使用者即可視為人類。

原來是大名鼎鼎的圖靈測試,真進階。現在2022年這個時間點,最出名的驗證碼是Google的reCAPTCHA,但是在國内是無法內建使用的。面對這個問題,著名CDN cloudflare是換了hCaptcha進行驗證。可以看一看,這篇文章《從 reCAPTCHA 遷移到 hCaptcha》。看了看hCaptcha官網,看樣子也是要收費的。有沒有一款,免費,不用連外網,還支援JDK17的簡單驗證碼庫類?那,下面就來嘗試一下:NanoCaptcha。

步驟

Maven

<dependency>
  <groupId>net.logicsquad</groupId>
  <artifactId>nanocaptcha</artifactId>
  <version>1.3</version>
</dependency>
           

生成驗證碼圖檔

public BufferedImage getCaptcha(HttpSession session) {
        ImageCaptcha imageCaptcha = new ImageCaptcha.Builder(200, 50).addFilter().addBorder().addNoise().addBackground().addContent().build();
        // 儲存驗證碼到目前會話
        String content = imageCaptcha.getContent();
        session.setAttribute(CAPTCHA_KEY, content);
        // 傳回圖檔
        return imageCaptcha.getImage();
    }
           

這裡核心代碼就一行:

ImageCaptcha imageCaptcha = new ImageCaptcha.Builder(200, 50).addFilter().addBorder().addNoise().addBackground().addContent().build();

使用NanoCaptcha生成驗證碼圖檔。

然後,将正确的驗證碼儲存到Spring的集中會話中。最後,傳回BufferedImage給請求。Controll方法類似如下:

@GetMapping(value = "/captcha", produces = "image/png")
    public BufferedImage getCaptcha(HttpSession session){
        return userService.getCaptcha(session);
    }
           

要想Spring正常傳回BufferdImage圖檔,還得注冊個Bean,如下:

@Bean
    public HttpMessageConverter<BufferedImage> bufferedImageHttpMessageConverter() {
        return new BufferedImageHttpMessageConverter();
    }
           

登入驗證

@Override
    public ResponseEntity<Result> authenticateUser(@Valid @RequestBody LoginRequest loginRequest, HttpSession httpSession)  {

        // 驗證驗證碼是否正确
        String content = (String) httpSession.getAttribute(CAPTCHA_KEY);
        httpSession.removeAttribute(CAPTCHA_KEY);
        if (!(StringUtils.hasText(content) && content.equals(loginRequest.getCaptcha()))) {
            throw new MyException("驗證碼驗證失敗");
        }
        ...
   }
           

這裡主要就是從會話取出之前生成的正确驗證碼,與前端送出的驗證碼進行比對。

**注意:**從會話中讀到正确的驗證碼之後,要從會話中删除掉這個資料。

測試

擷取驗證碼接口:

內建nanocaptcha庫生成登入驗證碼背景步驟測試總結參考:

總結

在使用NanoCaptcha庫之前,還嘗試使用了BotDetect庫,但是BotDetect不支援JDK17就放棄了。而且BotDetect本身自己說Java版本也是測試版本,再加上這邊也隻需要一款簡單夠用的驗證碼就可以了。

參考:

  • 驗證碼
  • reCAPTCHA
  • 《從 reCAPTCHA 遷移到 hCaptcha》
  • NanoCaptcha
  • SprintBoot returning a PNG from a Controller’s RequestMapping
  • BotDetect CAPTCHA Generator