简介
验证码功能位于cn.hutool.captcha
包中,核心接口为ICaptcha
,此接口定义了以下方法:
createCode
创建验证码,实现类需同时生成随机验证码字符串和验证码图片getCode
获取验证码的文字内容verify
验证验证码是否正确,建议忽略大小写write
将验证码图片写出到目标流中
其中write方法只有一个OutputStream
,ICaptcha
实现类可以根据这个方法封装写出到文件等方法。
AbstractCaptcha
为一个ICaptcha
抽象实现类,此类实现了验证码文本生成、非大小写敏感的验证、写出到流和文件等方法,通过继承此抽象类只需实现createImage
方法定义图形生成规则即可。
ps:国产的工具库,值得支持
官网地址:Hutool🍬一个功能丰富且易用的Java工具库,涵盖了字符串、数字、集合、编码、日期、文件、IO、加密、数据库JDBC、JSON、HTTP客户端等功能。
依赖引入
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.17</version>
</dependency>
使用示例
线段干扰验证码
@Test
public void lineCaptchaTest() {
//定义图形验证码的长和宽
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100);
//图形验证码写出,可以写出到文件,也可以写出到流
captcha.write("d:/line.png");
//输出code
Console.log(captcha.getCode());
//验证图形验证码的有效性,返回boolean值
captcha.verify("1234");
}
生产的验证形如:
圆圈干扰验证码
@Test
public void circleCaptchaTest() {
//定义图形验证码的长、宽、验证码字符数、干扰元素个数
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(800, 400);
//CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);
//图形验证码写出,可以写出到文件,也可以写出到流
captcha.write("d:/circle.png");
Console.log(captcha.getCode());
//验证图形验证码的有效性,返回boolean值
printVerify("1234",captcha);
}
生成的验证码形如:
扭曲干扰验证码
@Test
public void circleCaptchaTest() {
//定义图形验证码的长、宽、验证码字符数、干扰元素个数
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(800, 400);
//CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);
//图形验证码写出,可以写出到文件,也可以写出到流
captcha.write("d:/circle.png");
Console.log(captcha.getCode());
//验证图形验证码的有效性,返回boolean值
printVerify("1234",captcha);
}
生成的验证码形如:
verify代码
private void printVerify(String verifyCode, AbstractCaptcha captcha) {
Console.log("验证结果是:" + captcha.verify(verifyCode));
}
说明
1 框架验证默认使用的生成器是:RandomGenerator(随机数生成器),可以指定运算生成器,甚至自定义验证码生成器(实现CodeGenerator接口即可)
2 生成的验证码是存储在内存中的,后续要做输入验证需要使用同一个ICaptcha验证(当然也可以把验证码存储在其他地方,比如redis,然后标记一下,后续验证只要能取到对应的验证做验证即可)
实践案例
验证码的使用主要在登录和各种操作需要验证密码的场景下,以下是一个简单的登录验证码的使用
1 创建接口生产验证码图片
@GetMapping("captCha")
public R<CaptchaVo> captCha() {
CaptchaVo captchaVo = new CaptchaVo();
captchaVo.setImg(diyMath());
return R.success(captchaVo);
}
public String diyMath() {
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 45, 1, 4);
// 自定义验证码内容为四则运算方式
captcha.setGenerator(new MathGenerator());
// 重新生成code
captcha.createCode();
String code = captcha.getCode();
Console.log("运算生成的验证码是:" + code);
return captcha.getImageBase64();
}
/**
* 验证码信息
*/
@Data
public class CaptchaVo {
private String uuid;
/**
* 验证码图片
*/
private String img;
}
2 在html页面中通过<img src = "">标签渲染图片
function createCodeImg(domElement) {
debugger;
let uri = "/captCha"
let request = new XMLHttpRequest();
// 2、建立连接
// true:请求为异步 false:同步
request.open("GET", uri, false);
request.send();
let resSource = request.responseText;
let response = JSON.parse(request.responseText);
// 设置img元素的src属性为创建的URL
document.getElementById('loginImg').src = "data:image/gif;base64," + response.data.img;
}
这里通过get请求获取后端接口数据,在后端返回的图片信息时,返回的是图片的Base64数据信息,形如:
在前端直接通过该dom元素的src属性就可以渲染出来
为了保证在后续的登录验证时能校验验证码,后端回传了一个uuid到前端,作为绑定验证码的唯一凭据,验证码的数据是存储在redis中。在之后的登录验证时,前端将验证码关联的唯一凭据和验证码结果一起传给后端,后端通过唯一凭据查询redis,完成验证码的校验流程
如何计算结果
通过RandomGenerator生成的验证码无需计算,直接存储在redis中即可,如果是MathGenerator生成的验证码是需要计算结果的,如何获取计算结果呢?
hutool提供的工具:Calculator
@Test
public void mathStrCount() {
String testCode = "12*13";
double conversion = Calculator.conversion(testCode);
Console.log(conversion);
}
计算结果是:156.0
spring提供的工具:ExpressionParser
@Test
public void mathSpringCount() {
String testCode = "12*13";
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(testCode);
String result = exp.getValue(String.class);
Console.log(result);
}
计算结果是:156