Java Web项目使用图形验证码 — Kaptcha
一、验证码介绍
生成的主要方式:
1.使用Java原生的方式,其中包含了Servlet、AWT、ImageIO的使用;
2.使用开源库,例如Jcaptcha、Kaptcha...;
(各图形验证码开源库:http://www.oschina.net/project/tag/248/captcha?lang=19)
另外,生成code可以保存在Session或Cookie,也可以保存在缓存(例如,Redis);
需要验证的时候,需要把从Session或者缓存中取出并与请求的验证码进行校验;
二、项目中使用验证码
项目中使用的是Google的开源库 - Kaptcha;注意:本项目使用了Spring MVC;
1.引入Maven
<dependency>
<groupId>com.google.code</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
2.Spring配置Bean
更多Kaptcha配置请移步底部资料;
<!--图形验证码-->
<bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
<property name="config">
<bean class="com.google.code.kaptcha.util.Config">
<constructor-arg type="java.util.Properties">
<value>
kaptcha.border=yes
</value>
</constructor-arg>
</bean>
</property>
</bean>
3.Controller中代码实现
@RestController
@RequestMapping(value = "/verify", name = "图片验证码")
public class ValidateCoderController {
private Logger logger = LoggerFactory.getLogger(ValidateCoderController.class);
@Autowired
private Producer captchaProducer;
@RequestMapping(value = "/code", method = RequestMethod.GET, name = "图片验证码")
public void code(HttpServletResponse response,
@RequestParam(value = "mobilePhone", required = true) String mobilePhone,
@RequestParam(value = "captchaType", required = true) Integer captchaType) {
if (!StrUtils.isPhoneNumber(mobilePhone)) {
return;
}
CaptchaType type = getCaptchaTypeByCode(captchaType);
if (isTooOften(mobilePhone, type.getValue())) {
logger.info("号码{}获取{}图片验证码频繁", mobilePhone, type.getBundleKey());
return;
}
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.setHeader("Pragma", "no-cache");
response.setContentType("image/jpeg");
try (ServletOutputStream out = response.getOutputStream()) {
String capText = captchaProducer.createText().substring(0, 4);
BufferedImage bi = captchaProducer.createImage(capText);
ImageIO.write(bi, "jpg", out);
//设置验证码
RedisConnector.save(mobilePhone, capText, type.getValue());
/*移动端需要base64处理后返回,然后response的Headers不用配置;
此处需要使用ByteArrayOutputStream
BASE64Encoder encoder = new BASE64Encoder();
String base64String = encoder.encode(out.toByteArray());
*/
} catch (IOException e) {
e.printStackTrace();
logger.error("号码{}获取{}图片验证码失败", mobilePhone, type.getBundleKey());
}
}
private boolean isTooOften(String mobilePhone, String loginPre) {
String key = KeyUtils.getLimitKey(mobilePhone, loginPre);
if (RedisConnector.exists(key)) {
String countStr = RedisConnector.getData(key);
int count = Integer.parseInt(countStr);
if (count >= 30) {
return true;
}
}
return false;
}
}
4.验证码校验
需要使用的地方从Redis取出校验,这里需要注意的是:
1)Redis的Keys的生成工具类KeysUtils;
2)操作Redis的工具,以及Code的有效时间;
3)校验验证码成功需要使其失效;
Java原生方式:
http://tedhacker.top/2016/11/07/Java%E7%94%9F%E6%88%90%E9%AA%8C%E8%AF%81%E7%A0%81%E7%AE%80%E8%AE%B0/
https://www.jianshu.com/p/05409731abb8
使用Kaptcha:
https://www.jianshu.com/p/3a695783c5c1
http://blog.csdn.net/rambo_china/article/details/7720181