Kaptcha验证码介绍
◆Kaptcha 是谷歌开源的可高度配置的实用验证码生成工具
◆通过Kaptcha可阻拦大多数机器人脚本操作
◆Kaptcha典型应用于注册、登录、重要信息提交等用户交互
Kaptcha使用步骤
◆Kaptcha配置验证码生成参数
◆开发KapatchaControler生成验证码图片
◆将前台输入验证码与session保存的验证码进行比对
引入依赖
<!-- Kaptcha验证码组件 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<!-- 加密/解密组件 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.14</version>
</dependency>
在applicationContext.xml中配置Kaptcha
<!-- 配置Kaptcha -->
<bean id="kaptchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
<property name="config">
<bean class="com.google.code.kaptcha.util.Config">
<constructor-arg>
<props>
<!--验证码图片不生成边框-->
<prop key="kaptcha.border">no</prop>
<!-- 验证码图片宽度为120像素 -->
<prop key="kaptcha.image.width">120</prop>
<!-- 验证码图片字体颜色为蓝色 -->
<prop key="kaptcha.textproducer.font.color">blue</prop>
<!-- 每个字符最大占用40像素 -->
<prop key="kaptcha.textproducer.font.size">40</prop>
<!-- 验证码包含4个字符 -->
<prop key="kaptcha.textproducer.char.length">4</prop>
</props>
</constructor-arg>
</bean>
</property>
</bean>
测试用例
生成验证码图片的方法需要添加request和response这两个对象,我们都知道spring mvc底层它还是依赖于J2EE的WEB模块,也就是对于我们在实际开发中有一些特殊的场景,必须要使用到原生的请求或者响应对象,那此时就可以像当前这样书写,把原生对象放在参数列表中,这样在运行时spring ioc容器会将当前的请求与响应对象动态的注入到对应的参数中,就像当前的这个例子,因为验证码组件他在设计的时候就没有考虑到Spring的集成,所以必须要使用原生请求和原生的响应,因此我们将请求响应放在了参数列表中。
package com.imooc.reader.controller;
import com.google.code.kaptcha.Producer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
@Controller
public class KaptchaController {
@Resource
private Producer kaptchaProducer;//这个属性名要和刚才我们定义的id保持一致
@GetMapping("/verify_code")
public void createVerifyCode(HttpServletRequest request , HttpServletResponse response) throws IOException {
//设置过期时间 响应立即过期
response.setDateHeader("Expires",0);
//缓存控制 不缓存任何图片数据 不存储 不缓存 必须重新进行校验
response.setHeader("Cache-Control" , "no-store,no-cache,must-revalidate");
response.setHeader("Cache-Control" , "post-check=0,pre-check=0");
response.setHeader("Pragma" , "no-cache");
response.setContentType("image/png");
//生成验证码字符文本
String verifyCode = kaptchaProducer.createText();
request.getSession().setAttribute("kaptchaVerifyCode",verifyCode);//保存到session当中
System.out.println(request.getSession().getAttribute("kaptchaVerifyCode"));
BufferedImage image = kaptchaProducer.createImage(verifyCode);//创建验证码图片,将刚才生成的验证码作为参数添加
ServletOutputStream out = response.getOutputStream();//向浏览器输出
ImageIO.write(image, "png", out);//输出图片流
out.flush();
out.close();
}
}
前端引用:
<div class="input-group mt-4 ">
<div class="col-5 p-0">
<input type="text" id="verifyCode" name="vc" class="form-control p-4" placeholder="验证码">
</div>
<div class="col-4 p-0 pl-2 pt-0">
<!-- 验证码图片 -->
<img id="imgVerifyCode" src="/verify_code"
style="width: 120px;height:50px;cursor: pointer">
</div>
</div>
验证码的刷新与校验:
//重新发送请求,刷新验证码
function reloadVerifyCode(){
//请在这里实现刷新验证码
$("#imgVerifyCode").attr("src","/verify_code?ts=" + new Date().getTime());
}
//点击验证码图片刷新验证码
$("#imgVerifyCode").click(function () {
reloadVerifyCode();
});
//点击提交按钮,向/registe发起ajax请求
//提交请求包含四个参数
//vc:前台输入验证码 username:用户名 password:密码 nickname:昵称
$("#btnSubmit").click(function () {
//表单校验
var username = $.trim($("#username").val());
var regex = /^.{6,10}$/;
if (!regex.test(username)) {
showTips(true, "alert-danger", "用户名请输入正确格式(6-10位)");
return;
} else {
showTips(false);
}
var password = $.trim($("#password").val());
if (!regex.test(password)) {
showTips(true, "alert-danger", "密码请输入正确格式(6-10位)");
return;
} else {
showTips(false);
}
$btnReg = $(this);
$btnReg.text("正在处理...");
$btnReg.attr("disabled", "disabled");
//发送ajax请求
$.ajax({
url: "/registe",
type: "post",
dataType: "json",
data: $("#frmLogin").serialize(),
success: function (data) {
//结果处理,根据服务器返回code判断服务器处理状态
//服务器要求返回JSON格式:
//{"code":"0","msg":"处理消息"}
console.info("服务器响应:" , data);
if (data.code == "0") {
//显示注册成功对话框
$("#exampleModalCenter").modal({});
$("#exampleModalCenter").modal("show");
} else {
//服务器校验异常,提示错误信息
showTips(true, "alert-danger", data.msg);
reloadVerifyCode();
$btnReg.text("注 册");
$btnReg.removeAttr("disabled");
}
}
});
return false;
});
@PostMapping("/registe")
@ResponseBody
public Map registe(String vc, String username, String password , String nickname , HttpServletRequest request){
//正确验证码
String verifyCode = (String)request.getSession().getAttribute("kaptchaVerifyCode");//属性名要与前面设置的相同
//验证码对比
Map result = new HashMap();
if(vc == null || verifyCode == null || !vc.equalsIgnoreCase(verifyCode)){
result.put("code", "VC01");
result.put("msg", "验证码错误");
}else{
try {
memberService.createMember(username, password, nickname);
result.put("code", "0");//0代表处理成功
result.put("msg", "success");
}catch (BussinessException ex){
ex.printStackTrace();
result.put("code", ex.getCode());
result.put("msg", ex.getMsg());
}
}
return result;
}
@PostMapping("/check_login")
@ResponseBody
public Map checkLogin(String username, String password, String vc , HttpSession session){
//正确验证码
String verifyCode = (String)session.getAttribute("kaptchaVerifyCode");
//验证码对比
Map result = new HashMap();
if(vc == null || verifyCode == null || !vc.equalsIgnoreCase(verifyCode)){
result.put("code", "VC01");
result.put("msg", "验证码错误");
}else{
try {
Member member = memberService.checkLogin(username, password);
session.setAttribute("loginMember" , member);
result.put("code", "0");
result.put("msg", "success");
}catch (BussinessException ex){
ex.printStackTrace();
result.put("code", ex.getCode());
result.put("msg", ex.getMsg());
}
}
return result;
}