之前学redis就是为了搞验证码登录,现在redis入门了,就可以继续来搞我的验证码登录了,验证码登录其实可以用很多方法实现,比如session也可以。kaptcha是一个用于生成和验证 CAPTCHA 图像的java库,当然这样的库还有很多了,我也看了一些其他博客,最终选择了kaptcha这个库。这里简单记录一下我实现验证码登录的过程吧。
Nob.1 安装依赖
工欲善其事必先利其器,不用说导入依赖那肯定是第一步了。
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
Nob.2 配置Kaptcha
首先呢在我们项目的config目录下建立一个KaptchaConfig配置类,这里有什么作用呢?这里是用于对你要生成的验证码的各种设定,宽、高、干扰码、字母数字组合类型、长度等等,依据自己的需求去修改。我这里就给出我用的配置代码:
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.util.Properties;
@Component
public class KaptchaConfig {
@Bean
public DefaultKaptcha getDefaultKaptcha(){
com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha();
Properties properties = new Properties();
properties.put("kaptcha.border", "no");
properties.put("kaptcha.textproducer.font.color", "black");
properties.put("kaptcha.image.width", "150");
properties.put("kaptcha.image.height", "40");
properties.put("kaptcha.textproducer.font.size", "30");
properties.put("kaptcha.session.key", "verifyCode");
properties.put("kaptcha.textproducer.char.space", "5");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
然后呢我顺便补充一下Kaptcha的一些配置项笔记:
1. 基本配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
kaptcha.border | yes | 是否显示边框。可选值:yes(显示边框)、no(不显示边框)。 |
kaptcha.border.color | black | 边框颜色。支持颜色名称(如 black)或 RGB 值(如 0,0,0)。 |
kaptcha.border.thickness | 1 | 边框厚度。取值范围:正整数。 |
kaptcha.image.width | 200 | 验证码图片的宽度。 |
kaptcha.image.height | 50 | 验证码图片的高度。 |
kaptcha.session.key | KAPTCHA_SESSION_KEY | 验证码存储在 Session 中的键名。 |
kaptcha.session.date | KAPTCHA_SESSION_DATE | 验证码生成时间存储在 Session 中的键名。 |
2. 文本配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
kaptcha.textproducer.char.string | abcde2345678gfynmnpwx | 验证码字符集。可以自定义字符集,例如 0123456789 表示仅使用数字。 |
kaptcha.textproducer.char.length | 5 | 验证码字符的长度。 |
kaptcha.textproducer.font.names | Arial, Courier | 验证码字体。可以指定多个字体,用逗号分隔。 |
kaptcha.textproducer.font.size | 40 | 验证码字体大小。 |
kaptcha.textproducer.font.color | black | 验证码字体颜色。支持颜色名称(如 black)或 RGB 值(如 0,0,0)。 |
kaptcha.textproducer.char.space | 2 | 字符之间的间距。 |
3. 干扰配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
kaptcha.noise.color | black | 干扰线颜色。支持颜色名称(如 black)或 RGB 值(如 0,0,0)。 |
kaptcha.noise.impl | DefaultNoise | 干扰线实现类。可以自定义干扰线实现类。 |
kaptcha.obscurificator.impl | WaterRipple | 验证码扭曲效果实现类。可选值:WaterRipple(水波纹)、ShadowGimpy(阴影扭曲)等。 |
4. 背景配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
kaptcha.background.clear.from | lightGray | 背景渐变起始颜色。支持颜色名称(如 lightGray)或 RGB 值(如 211,211,211)。 |
kaptcha.background.clear.to | white | 背景渐变结束颜色。支持颜色名称(如 white)或 RGB 值(如 255,255,255)。 |
5. 其他配置
| 配置项 | 默认值 | 说明 |
|---|---|---|
kaptcha.producer.impl | DefaultKaptcha | 验证码生成器实现类。可以自定义验证码生成器。 |
kaptcha.word.impl | DefaultWordRenderer | 验证码文本渲染器实现类。可以自定义文本渲染器。 |
Nob.3 实现验证码图片获取接口
我这里是如何实现的呢,首先,使用 DefaultKaptcha 生成一个随机的验证码文本,并通过 Redis 存储该验证码文本,关联一个唯一的 captchaKey,设置过期时间为 5 分钟。然后,生成验证码图片并将其转换为字节流。最后,将生成的验证码图片以 JPEG 格式通过 HTTP 响应输出,同时将 captchaKey 放入响应头,方便前端使用该 key 进行后续验证。
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.yaojie.service.redis.RedisStringService;
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.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.UUID;
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
private DefaultKaptcha captchaProducer;
@Autowired
private RedisStringService redisStringService; // 使用封装的 RedisStringService
@GetMapping("/kaptcha")
public void generateCaptcha(HttpServletResponse response) throws Exception {
// 生成验证码字符串
String verifyCode = captchaProducer.createText();
// 生成唯一的 captchaKey
String captchaKey = UUID.randomUUID().toString();
// 将验证码存储到 Redis 中,设置过期时间为 5 分钟
redisStringService.setAndTime(captchaKey, verifyCode, 5 * 60);// 5 分钟
// 生成验证码图片
BufferedImage challenge = captchaProducer.createImage(verifyCode);
ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
ImageIO.write(challenge, "jpg", imgOutputStream);
// 将 captchaKey 写入响应头,方便前端获取
response.setHeader("captchaKey", captchaKey);
// 将验证码图片写入响应
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
ServletOutputStream responseOutputStream = response.getOutputStream();
responseOutputStream.write(imgOutputStream.toByteArray());
responseOutputStream.flush();
responseOutputStream.close();
}
}
这里的redis可以参照我上一篇的笔记Redis的入门与springboot中的基本使用-CSDN博客,但是我这里改了一点,之前没有封装String带时间设置的set函数,这里加一下:
/**
* 设置字符串类型的值,并指定过期时间(秒)
*
* @param key 键
* @param value 值
* @param timeout 过期时间(秒)
*/
public void setAndTime(String key, String value, long timeout) {
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
好了我们测试一下这个接口,打开apifox运行一下,发现确实可以拿到验证码,去redis里看一下有没有数据,也确实有,也有过期时间,OK啊。



Nob.4 登录接口添加验证码校验逻辑
前端那边通过获取验证码接口获取了验证码图片,也可以从请求头里面拿到captchaKey,登录时就需要将账号密码,验证码,验证码key一同传到后端这边来,那我们再根据前端传过来的captchaKey去redis里面查找对应的value,再与前端传过来的验证码verifyCode对比,就可以实现简单的验证码校验逻辑了,这里我写的比较简单,可能不严谨,但大致思路应该是这样了,大家可以按照自己的需求去修改逻辑。
@PostMapping("/login")
public R login(@RequestParam("captchaKey") String captchaKey, // 前端传递的 captchaKey
@RequestParam("verifyCode") String verifyCode, // 前端传递的验证码
@RequestBody @Validated Users users) {
// 从 Redis 中获取验证码
String redisVerifyCode = redisStringService.get(captchaKey);
// 验证验证码
if (redisVerifyCode == null || !redisVerifyCode.equalsIgnoreCase(verifyCode)) {
return R.error().message("验证码错误或已过期!");
}
Users u = usersService.findByAccount(users.getAccount());
if (u == null) {
return R.error().message("登录失败!请检查您的账号是否存在问题!");
}
if (Md5Util.getMD5String(users.getPassword()).equals(u.getPassword())) {
Map<String, Object> claims = new HashMap<>();
claims.put("account", u.getAccount());
claims.put("password", u.getPassword());
String token = JwtUtil.genToken(claims);
return R.ok().data("token", token);
}
return R.error().message("密码错误!");
}
好了,再去apifox里面测试一下接口行不行,可以看到,OK了,到这里,简单的验证码登录就做好了。


Nob.5 总结
验证码登录实现起来还是不难,就是学redis花费了一点时间,每天进步一点点!










