简单介绍
Kaptcha是一个简单的图片验证码生成工具,小巧,使用起来还是比较顺手的。
查了一下,官网项目很久没有更新了,估计现在也没有人维护了,因为是google的域名,所以想看的话还得自己去翻墙。
工作原理
图片验证码的工作原理都是一样的,服务端生成随机字符串,以图片的形式给到客户端,客户端用户输入图片上的验证码,服务端验证用户输入的验证码是否正确。
验证码存在的意义是为了系统安全,确保客户端用户是个活生生的人,而不是机器程序在搞恶意攻击。
项目实践
搭建一个spring boot项目,用vue做一个简单的图片验证码页面,最后给出项目源码,仅供参考。
第一步:创建一个spring boot web项目,可正常启动,接收请求并响应。
第二步:引入Kaptcha依赖jar包,就一个,也是最新版本。
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
第三步:根据需求对Kaptcha进行相关配置。
/**
* Kaptcha 详细属性配置项可查看 {@link com.google.code.kaptcha.Constants} 类
*
* @return
*/
@Bean
public DefaultKaptcha getDefaultKaptcha() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty(Constants.KAPTCHA_BORDER, "yes");// 图片边框
properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "105,179,90");// 边框颜色
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");// 字体颜色
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "10");
properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "160");// 图片宽
properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "50");// 图片高
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "30");// 字体大小
properties.setProperty(Constants.KAPTCHA_SESSION_CONFIG_KEY, "verificationCode");// session key
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");// 验证码长度
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体,楷体,微软雅黑");// 字体
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
这是spring boot的代码配置方法,如果是传统的spring项目,需要使用xml配置,配置参数都是一样的,形式不一样。
全面详细的配置项可以参考下表:
Constant | 描述 | 默认值 |
---|---|---|
kaptcha.border | 图片边框,合法值:yes , no | yes |
kaptcha.border.color | 边框颜色,合法值:r,g,b (and optional alpha) 或者 white,black,blue | black |
kaptcha.border.thickness | 边框厚度,合法值:> 0 | 1 |
kaptcha.image.width | 图片宽度 | 200 |
kaptcha.image.height | 图片高度 | 50 |
kaptcha.producer.impl | 图片实现类 | com.google.code.kaptcha.impl.DefaultKaptcha |
kaptcha.textproducer.impl | 文本实现类 | com.google.code.kaptcha.text.impl.DefaultTextCreator |
kaptcha.textproducer.char.string | 文本集合,验证码值从此集合中获取 | abcde2345678gfynmnpwx |
kaptcha.textproducer.char.length | 验证码长度 | 5 |
kaptcha.textproducer.font.names | 字体 | Arial, Courier |
kaptcha.textproducer.font.size | 字体大小 | 40px |
kaptcha.textproducer.font.color | 字体颜色,合法值: r,g,b 或者 white,black,blue | black |
kaptcha.textproducer.char.space | 文字间隔 | 2 |
kaptcha.noise.impl | 干扰实现类 | com.google.code.kaptcha.impl.DefaultNoise |
kaptcha.noise.color | 干扰 颜色,合法值: r,g,b 或者 white,black,blue | black |
kaptcha.obscurificator.impl | 图片样式: 水纹 com.google.code.kaptcha.impl.WaterRipple 鱼眼 com.google.code.kaptcha.impl.FishEyeGimpy 阴影 com.google.code.kaptcha.impl.ShadowGimpy | com.google.code.kaptcha.impl.WaterRipple |
kaptcha.background.impl | 背景实现类 | com.google.code.kaptcha.impl.DefaultBackground |
kaptcha.background.clear.from | 背景颜色渐变,开始颜色 | light grey |
kaptcha.background.clear.to | 背景颜色渐变, 结束颜色 | white |
kaptcha.word.impl | 文字渲染器 | com.google.code.kaptcha.text.impl.DefaultWordRenderer |
kaptcha.session.key | Kaptcha提供的常量值,可做服务端存储的key值 | KAPTCHA_SESSION_KEY |
kaptcha.session.date | Kaptcha提供的常量值,可做服务端存储的key值 | KAPTCHA_SESSION_DATE |
第四步:配置好Kaptcha属性以后,在需要的地方注入defaultKaptcha对象。
private DefaultKaptcha defaultKaptcha;
@Autowired
public void setDefaultKaptcha(DefaultKaptcha defaultKaptcha) {
this.defaultKaptcha = defaultKaptcha;
}
这里没有使用字段注入(Field injection)方式,因为最近升级了IDE,发现使用字段注入的时候,IDE会提醒:Field injection is not recommended。查了一下,发现我们在Spring项目里使用最多的注入方式竟然是Spring最不推荐的方式!所以,以后还是改用另外两种方式吧:构造器注入,setter注入。
第五步:提供生成图片验证码的接口,验证码在服务端存储一份,同时转换成图片形式,返回给客户端。
随机字符串的生成可以使用Kaptcha提供的方法,也可以自己定义,反正就是个随机字符串而已。
@GetMapping("/verificationCode")
public void verificationCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
// 生成验证码并保存在session中
String text = defaultKaptcha.createText();
// Constants.KAPTCHA_SESSION_KEY 是 kaptcha 提供好的 session key,可以直接拿来用,通常不需要自己再定义
request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, text);
// 生成验证码图片
BufferedImage image = defaultKaptcha.createImage(text);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", baos);
// 响应给客户端
ServletOutputStream responseOutputStream = response.getOutputStream();
responseOutputStream.write(baos.toByteArray());
responseOutputStream.flush();
responseOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
第六步:提供接口,校验客户端输入验证码的正确性。
需要注意的是,一个验证码应该只能使用一次,不论验证通过与否,都应该删除服务端储存的验证码,让客户端重新获取并进行验证,防止客户端用户或者机器程序不断试错。
@PostMapping("/login")
public String login(HttpServletRequest request, String verificationCode) {
HttpSession session = request.getSession();
String sessionCode = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
if (sessionCode == null || sessionCode.isEmpty()) return "failed";
if (!sessionCode.equals(verificationCode)) {// 验证失败
session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
return "failed";
} else {// 验证成功
session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
return "success";
}
}
第七步:编写客户端页面逻辑,为用户提供验证功能。
<div id="app" class="container">
<div class="row justify-content-md-center">
<div class="col-6 border m-5 p-5">
<div class="form-group">
<img v-bind:src="imgSrc" v-on:click="changeCode" alt="验证码"/>
<input v-model="verificationCode" class="form-control form-control-lg col-6 my-3" placeholder="输入验证码"/>
<button v-on:click="submit" class="btn btn-success col-6">登录</button>
<p class="h3 text-danger my-3">{{ message }}</p>
</div>
</div>
</div>
</div>
<script>
let app = new Vue({
el: '#app',
data: {
imgSrc: '/verificationCode',
verificationCode: '',
message: ''
},
methods: {
changeCode: function () {
// 后面添加参数t起到清除缓存作用
this.imgSrc = "/verificationCode?t=" + new Date() * 1;
},
submit: async function () {
try {
if (this.verificationCode == '') {
this.message = "验证码不能为空";
return;
}
const response = await axios.post('/login?verificationCode=' + this.verificationCode);
let resp = response.data;
if (resp == 'success') {
this.message = "验证码输入正确";
} else {
this.message = "验证码输入不正确";
this.changeCode();
}
} catch (error) {
console.error(error);
}
}
}
});
</script>
项目源码
项目地址:demo-kaptcha,运行方式:
// maven 启动
mvn spring-boot:run
// 访问地址
http://localhost:8080/