redis+kaptcha实现验证码登录
本文最后更新于-1天前,其中的信息可能已经过时,如有错误请发送邮件到2392862431@qq.com

之前学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.borderyes是否显示边框。可选值:yes(显示边框)、no(不显示边框)。
kaptcha.border.colorblack边框颜色。支持颜色名称(如 black)或 RGB 值(如 0,0,0)。
kaptcha.border.thickness1边框厚度。取值范围:正整数。
kaptcha.image.width200验证码图片的宽度。
kaptcha.image.height50验证码图片的高度。
kaptcha.session.keyKAPTCHA_SESSION_KEY验证码存储在 Session 中的键名。
kaptcha.session.dateKAPTCHA_SESSION_DATE验证码生成时间存储在 Session 中的键名。

2. 文本配置

配置项默认值说明
kaptcha.textproducer.char.stringabcde2345678gfynmnpwx验证码字符集。可以自定义字符集,例如 0123456789 表示仅使用数字。
kaptcha.textproducer.char.length5验证码字符的长度。
kaptcha.textproducer.font.namesArial, Courier验证码字体。可以指定多个字体,用逗号分隔。
kaptcha.textproducer.font.size40验证码字体大小。
kaptcha.textproducer.font.colorblack验证码字体颜色。支持颜色名称(如 black)或 RGB 值(如 0,0,0)。
kaptcha.textproducer.char.space2字符之间的间距。

3. 干扰配置

配置项默认值说明
kaptcha.noise.colorblack干扰线颜色。支持颜色名称(如 black)或 RGB 值(如 0,0,0)。
kaptcha.noise.implDefaultNoise干扰线实现类。可以自定义干扰线实现类。
kaptcha.obscurificator.implWaterRipple验证码扭曲效果实现类。可选值:WaterRipple(水波纹)、ShadowGimpy(阴影扭曲)等。

4. 背景配置

配置项默认值说明
kaptcha.background.clear.fromlightGray背景渐变起始颜色。支持颜色名称(如 lightGray)或 RGB 值(如 211,211,211)。
kaptcha.background.clear.towhite背景渐变结束颜色。支持颜色名称(如 white)或 RGB 值(如 255,255,255)。

5. 其他配置

配置项默认值说明
kaptcha.producer.implDefaultKaptcha验证码生成器实现类。可以自定义验证码生成器。
kaptcha.word.implDefaultWordRenderer验证码文本渲染器实现类。可以自定义文本渲染器。

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花费了一点时间,每天进步一点点!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇