整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

如何在Spring Boot项目中生成图形验证码

家好!我是黑客之家小编,黑客之家头条号

分享黑客技术,GO、Python、Kotlin、Android、Java编程知识,科技资讯等

喜欢的朋友可以关注我的头条号!

图形验证码是我们经常会用到的,例如在app或者网站注册的时候,登录的时候等等。图形验证码属于验证码的一种。

图形验证码

验证码(CAPTCHA)是 “Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。

采用图形验证码是为了数据的安全,防止某些破解软件,进行无限尝试破解,图形的话,软件无法识别,或识别的慢,这样更加安全。

理论上图形验证码是比较安全的,但是随着技术的发展,特别是机器学习和人工智能技术的发展,图形验证码也变得不安全了,今天我们将要生成的数字字母组合的验证码,其实已经不够安全了,生成效果如下:

这种验证码还是容易被机器识别的,后续的文章中会介绍如何采用程序识别这类图形验证码。

接着说图形验证码的生成,今天我们采用的是kaptcha。kaptcha是一个可配置验证码生成工具包,我们按照kaptcha的配置表配置就可以了。

在使用kaptcha之前,要导入kaptcha的包,依赖如下:

<dependency>
 <groupId>com.github.penggle</groupId>
 <artifactId>kaptcha</artifactId>
 <version>2.3.2</version>
</dependency>

在Spring Boot项目中新建一个KaptchaConfig.java文件,具体代码如下:

package com.example.demo.config;
/**
 * Created by hacker on 2019-07-16.
 */
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
 * @author hacker
 */
@Configuration
public class KaptchaConfig {
 @Bean
 public DefaultKaptcha getDefaultKaptcha() {
 DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
 Properties properties = new Properties();
 properties.setProperty("kaptcha.border", "yes");
 properties.setProperty("kaptcha.border.color", "105,179,90");
 properties.setProperty("kaptcha.textproducer.font.color", "blue");
 properties.setProperty("kaptcha.image.width", "110");
 properties.setProperty("kaptcha.image.height", "40");
 properties.setProperty("kaptcha.textproducer.font.size", "30");
 properties.setProperty("kaptcha.session.key", "code");
 properties.setProperty("kaptcha.textproducer.char.length", "4");
 properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
 Config config = new Config(properties);
 defaultKaptcha.setConfig(config);
 return defaultKaptcha;
 }
}

这样kaptcha的样式和颜色字体等就设置好了,接着就是生成图形上的字符,同时通过二进制流的形式把生成的图片返回给前端。

代码如下:

package com.example.demo.controller;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
/**
 * <p>
 * 用户信息表 前端控制器
 * </p>
 *
 * @author hacker
 */
@RestController
@RequestMapping("/api/")
public class UserInfoController {
 @Autowired
 private DefaultKaptcha captchaProducer;
 @GetMapping("/getVerifyCode")
 public void getVerifyCode(HttpServletRequest request, HttpServletResponse response) throws Exception {
 String createText = captchaProducer.createText();
 request.getSession().setAttribute("verifyCode", createText);
 response.setHeader("Cache-Control", "no-store");
 response.setHeader("Pragma", "no-cache");
 response.setDateHeader("Expires", 0);
 response.setContentType("image/jpeg");
 BufferedImage challenge = captchaProducer.createImage(createText);
 ServletOutputStream outputStream = response.getOutputStream();
 ImageIO.write(challenge, "jpg", outputStream);
 try {
 outputStream.flush();
 } finally {
 outputStream.close();
 }
 }
}

这样我们就可以用GET方式获取到生成的图形验证码了。

为了能在浏览器里显示我们这里采用thymeleaf模板。

在pom.xml文件中引入thymeleaf依赖如下:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

之后在templates文件夹下新建一个index.html文件,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>CAPTCHA</title>
 <script type="text/javascript">
 function refresh() {
 document.getElementById('captcha_img').src = "/api/getVerifyCode?" + Math.random();
 }
 </script>
</head>
<body>
<div>
 <img id="captcha_img" alt="点击更换" title="点击更换"
 onclick="refresh()" src="/api/getVerifyCode"/>
</div>
</body>
</html>

这样一个简单前端显示图形验证码就做好了,之后我们输入http://localhost:8090/,就可以访问了,8090换成自己对应的端口。

图形验证码

点击图片可以切换图形验证码。至此,图形验证码功能结束!

如果觉得文章对你有帮助,欢迎关注,点赞,转发,评论!后续文章会介绍如何通过程序识别今天生成的图形验证码,感兴趣的同学,可以持续关注!

相关阅读:

基于spring boot快速搭建Java服务器

Spring Boot项目部署简单方便的Shell脚本

推荐一款Spring Boot中非常好用的插件

网页设计中,尤其表单填写提交过程中,为防止机器自动登录,很多网页都采用验证码技术,允许用户输入而尽量避免自动登录。验证码实现的方法有很多,PHP绘图技术可以在服务端生成验证码并发送客户端,HTML5技术下可以使用canvas与JS脚本实现在客户端浏览器自动生成验证码。本文给出JS+Canvas验证码的解决措施,所制作验证码实现效果如下图所示:

验证码实现效果动态图


实现原理

本例验证码的实现主要包括验证码字符串的生成、背景干扰点实现及干扰直线的生成三部分。最终通过canvas绘图技术将生成的验证码字符串、背景及干扰直线显示到画布上。主要涉及技术或知识点包括canvas绘图技术、数组、鼠标点击事件、随机函数等。以下从验证字符串、背景干扰点及干扰直线三方面对实现过程进行说明。

验证字符串

验证字符串部分主要借助数组存储验证码所有字符,通过调用Math对象的随机函数获取数组下标,并通过数组下表读取数组元素,将读取的数组元素组装成完整字符串。其实现核心代码如下:

验证字符串获取核心代码

如上图所示,本例验证码字符包括数字与大写字母,getCode函数返回值即为4位验证码字符串。

背景干扰点

背景干扰点可以直接使用canvas对应的绘图方法进行绘制,本例为简化开发过程,降低难度直接使用drawImage绘图方式加载背景图片,实现干扰点效果。背景图片如下:

背景干扰点图片

通过调用drawImage方法,指定截取的坐标位置参数,可实现背景干扰点的动态变化效果,背景干扰点实现核心代码如下:

背景干扰点实现代码

其中getXsize与getYsize为获取绘图截取背景图片的坐标位置,通过使用随机函数实现从背景图片不同位置截取进行绘图输出。

干扰直线

干扰直线实现较为简单,直接通过JS提供的moveTo与lineTo方法完成直线的绘制,本例绘制了两条直线,一条为黑色干扰线,一条为白色干扰线。在绘制过程两端点需要使用Math随机函数生成符合条件随机坐标。干扰直线相关实现代码如下:

干扰直线实现核心代码

干扰直线实现核心代码如上图,其中getLsize方法主要用于获取随机端点Y轴坐标值。strokeStyle主要用于设置绘图直线的颜色。

验证码显示输出

验证码的显示输出主要使用fillText()方法在canvas指定位置进行文字输出,本例使用第三方ttf字体,因此在HTML页面中对字体进行了加载。验证码显示输出实现代码如下:

验证码绘制

验证码显示输出核心代码如上图所示,其中myfont为加载的第三方字体。

绘图基础部分

绘图基础部分主要包括前端canvas元素的布局等。包括属性的设置,js部分元素的获取及属性设置等。

其他工作

我们一般接触的验证码,都可以点击图片实现验证码的刷新,因此本例为canvas标记添加了onclick事件,将所有验证码生成的代码封装到showCode()函数中,通过调用showCode函数实现验证码的刷新。本例完整JS脚本部分代码如下:

JS实现脚本代码


本头条号长期关注编程资讯分享;编程课程、素材、代码分享及编程培训。如果您对以上方面有兴趣或代码错误、建议与意见,可以联系作者,共同探讨。期待大家关注!如需案例完整代码请关注并私信,往期前端设计文章链接如下:

  1. 前端设计-Ajax技术及实例展示
  2. 前端设计-响应式页面开发基础
  3. Web开发前端、后端与全栈的区别是什么?

近有同事在调研微信小程序,准备把我们的 landing page(LP)页面,迁移到小程序里,提高用户体验,提升转化率。

在LP里,遇到个很常见的问题,用户通过手机号注册,发送短信验证码需要防刷,目前在 h5 上使用的是 图形验证码+极验。一上来,就遇到了图形验证码的问题。小程序和 web 开发不同,不会 自动处理 http 请求的 cookie。

通常在 web 上,我们会把图形验证码存储到用户 session 里,然后在发送短信的接口,判断用户提交的图形验证码和 session 里的值是否相等,这里依赖浏览器自动会处理 cookie 的读写来实现的。但是小程序里,需要开发者主动来管理 cookie 等,并且在图片请求中,也 不能 主动设置cookie,导致之前 web 上的图形验证码完全失效。

在网上发现提到小程序里的图形验证码实现的文章很少,就有一篇这个 wechat-captcha ,但是作者这是纯前端用 canvas 来绘制的图形验证码,显然,图形验证码的生成,只能放在 server 端,这种方案,就需要有一种很好的方式,来讲server端生成的图形验证码的值,传递到前端来。没想到有什么方案,能从server端比较稳妥的传递图形验证码的值到小程序里,只能看看其他大厂是怎么做的了。

server 返回图片base64编码

同事发现饿了么的小程序里,是有图形验证码的,那就先来看看饿了么的同学是怎么实现的呢。经过抓包,很明显能看到饿了么的图片验证码请求,是通过 js 来发起的,server 端返回的图形验证码的 base64 编码,没有继续看后续是怎么把 base64 编码渲染到出来的,但肯定是有办法将 base64 的图形验证码绘制到 canvas 上的。

其实这里是有个疑问的,在抓包的时候,发现在请求图形验证码的时(POST),并没有带上 cookie,也就是说,饿了么并没有用 cookie-session 来存储某个手机号对应的图形验证码;并且用户的手机号,拼在了请求的 url 里,似乎在server端是通过其他方式,来存储的手机号和图形验证码的关联。

我不太理解的是,既然用户手机号已经放在请求的 path 里了,为什么要使用 POST 来单独请求图验的 base64 编码,再渲染到 canvas 上,为什么不直接拼一个 GET 的 url,同样把手机号放进去,然后接口直接输出二进制的图片数据,这样就可以直接把 url 赋值给小程序的 image 组件了。

饿了么抓包如下(响应中的 captcha_image 字段就是 png 图片的 base64编码):

使用 WebView

然后又看了下美团的小程序,直接没用图形验证码,而是用的类似极验的滑块。猜想也是使用了 canvas 之类的技术来实现的,抓包才发现,原来是用的 web-view组件来引用的 html 页面。刚重新抓包过程中,虽然后端响应接口确实返回了一个 h5 的滑块页面URL,但是没看到有加载这个页面,看来美团也 没有 用 web-view 来加载 h5。

美团抓包如下: