需要实现一个验证码登录的功能需求。这个需求挺简单的,主要实现验证码图片生成给前端,然后,在登录接口比对验证码即可。刚拿到这个需求,好久没有搞过登录这一块了,所以,查了一下相关验证码的知识。下面是维基百科中关于验证码的说明:
全自动区分计算机和人类的图灵测试(英语: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。
net.logicsquad nanocaptcha 1.3
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,如下:
@Beanpublic HttpMessageConverter bufferedImageHttpMessageConverter() {return new BufferedImageHttpMessageConverter();}
@Overridepublic ResponseEntity 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库之前,还尝试使用了BotDetect库,但是BotDetect不支持JDK17就放弃了。而且BotDetect本身自己说Java版本也是测试版本,再加上这边也只需要一款简单够用的验证码就可以了。