
所用相关接口如上:
没有接口时报错如下:
一、验证码生成与 Redis 暂存
1. Redis 环境准备
(1)Redis 启动与运行
- 解压 Redis 压缩包后,双击
redis-server.exe,弹出运行窗口且提示 "Ready to accept connections" 即启动成功(禁止关闭该窗口); - 默认配置:端口 6379,内置 0-15 共 16 个数据库,默认使用第 0 个。
(2)Redis 图形化工具(RedisDesktopManager)
- 解压双击
rdm.exe启动工具,新建连接:- 自定义命名,Host 填写 127.0.0.1,端口 6379,默认无密码;
- 先测试连接,确认可用后保存,可通过工具手动创建 key-value 数据验证 Redis 可用性。
使用redis数据库实现暂存
redis数据库存在0-15个
解压redis压缩包并直接双击redis-server.exe即可运行

弹出该弹窗即算运行成功(注意不要关)
此刻即可通过redis命令在控制台(双击redis-cli.exe)使用
redis的图形化工具是RedisDesktopManager
使用方式同上解压并双击rdm.exe

这就是图形化工具
然后新建连接服务器连接服务,自定义命名,默认无密码,host:127.0.1
若之前没有持续运行redis-server.exe弹窗或创建连接时已关闭,应该先连接测试再确定

这里可以新建key:value型数据,例如:

(3)项目中 Redis 配置
在application.yml添加如下配置:
bash
redis:
host: 127.0.0.1 # Redis服务地址
port: 6379 # 默认端口
database: 0 # 使用第0个数据库
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-aliases-package: com.qcby.communityTest1.entity
2. 验证码生成接口(/captcha)
(1)核心代码
java
@GetMapping("/captcha")
public Result getCaptcha(){
// 1. 生成验证码图片(宽130、高38、4位字符)
SpecCaptcha specCaptcha= new SpecCaptcha(130,38,4);
// 2. 获取验证码文本并统一转大写(避免大小写校验问题)
String code = specCaptcha.text().toUpperCase();
// 3. 生成唯一UUID作为Redis的Key(无时间/MAC信息,保证唯一性)
String uuid = IdUtil.simpleUUID();
// 4. 存入Redis:Key=uuid,Value=code,过期时间120秒(自动失效)
redisTemplate.opsForValue().set(uuid,code,120, TimeUnit.SECONDS);
// 5. 封装返回数据(生产环境禁止返回明文code)
HashMap<String, String> r = new HashMap<>();
r.put("uuid",uuid); // 用于后续校验时获取Redis中的验证码
r.put("code",code); // 测试用,生产环境删除
r.put("captcha",specCaptcha.toBase64()); // 验证码图片转Base64,前端直接渲染
return Result.ok().put("data",r);
}
(2)关键知识点
- SpecCaptcha:第三方验证码工具,支持自定义尺寸 / 位数,生成的图片可转 Base64 格式;
- Redis 存储优势:利用过期特性避免验证码长期有效,UUID 作为 Key 防止重复;
- 注意事项:生产环境仅返回 uuid 和 Base64 图片,不返回明文验证码,降低泄露风险。
3. 验证码二次校验逻辑
前端提交表单(如登录)时携带uuid和用户输入的验证码,后端校验步骤:
- 从请求参数中获取
uuid和userInputCode; - 通过
redisTemplate.opsForValue().get(uuid)获取 Redis 中存储的验证码; - 对比
userInputCode.toUpperCase()与存储的验证码:- 一致:校验通过,删除 Redis 中该 uuid 对应的 Key(防止重复使用);
- 不一致 / Redis 无数据(过期 / 不存在):校验失败,返回提示信息。
二、JWT 令牌工具类(JwtUtil)
1. 功能说明
基于 JJWT 实现 JWT 令牌的生成与校验,用于用户验证码校验通过后颁发令牌,后续接口通过令牌完成身份校验,配置参数从配置文件解耦读取。
2. 核心配置
在application.yml添加 JWT 相关配置:
jwt:
expire: 3600000 # 令牌过期时间(1小时,单位:毫秒)
secret: abc123456789 # 签名密钥(生产环境建议使用复杂随机串)
subject: community-user # 令牌主题(标识业务场景)
3. 核心代码
java
@ConfigurationProperties(prefix = "jwt") // 读取配置文件中jwt前缀的配置
@Component
public class JwtUtil {
// 配置属性:过期时间、签名密钥、令牌主题
private long expire;
private String secret;
private String subject;
/**
* 生成JWT令牌
* @param userId 自定义载荷:存储用户ID(可扩展用户名、角色等)
* @return JWT令牌字符串
*/
public String createToken(String userId) {
return Jwts.builder()
// 自定义载荷:存储业务标识
.claim("userId", userId)
// 标准载荷:令牌主题
.setSubject(subject)
// 标准载荷:过期时间(当前时间+配置的过期时长)
.setExpiration(new Date(System.currentTimeMillis() + expire))
// 标准载荷:令牌ID(UUID保证唯一性)
.setId(UUID.randomUUID().toString())
// 签名算法:HS256 + 签名密钥(防止令牌篡改)
.signWith(SignatureAlgorithm.HS256, secret)
// 组装为JWT字符串
.compact();
}
/**
* 校验令牌有效性
* @param token 待校验的令牌
* @return true-有效,false-无效(过期/篡改/格式错误)
*/
public boolean checkToken(String token){
if(StringUtils.isEmpty(token)){
return false;
}
try {
// 解析令牌:验证签名和过期时间,失败则抛出异常
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
} catch (Exception e) {
// 捕获所有异常(过期、签名错误等),判定令牌无效
return false;
}
return true;
}
// getter/setter:用于@ConfigurationProperties注入配置
public long getExpire() { return expire; }
public void setExpire(long expire) { this.expire = expire; }
public String getSecret() { return secret; }
public void setSecret(String secret) { this.secret = secret; }
public String getSubject() { return subject; }
public void setSubject(String subject) { this.subject = subject; }
}
4. 关键
-
@ConfigurationProperties:实现配置参数解耦,避免硬编码;
-
JWT 结构:由头部(算法)、载荷(自定义 / 标准信息)、签名(防篡改)三部分组成;
-
令牌校验:解析时捕获所有异常(过期、签名错误、格式非法),统一判定为令牌无效;
-
扩展建议:新增方法从令牌中解析 userId,示例:
javapublic String getUserIdFromToken(String token) { Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); return claims.get("userId", String.class); }
三、完整流程与注意事项
1. 流程
用户登录场景:
- 前端请求
/captcha接口,获取 uuid 和 Base64 验证码图片,展示给用户; - 用户输入验证码,前端携带
uuid、用户输入的验证码、账号密码提交登录请求; - 后端通过 uuid 从 Redis 获取存储的验证码,对比用户输入内容,校验通过后调用 JwtUtil 生成令牌;
- 后端返回 JWT 令牌给前端,前端存储令牌(如 localStorage);
- 后续前端请求需认证的接口时,携带令牌,后端通过 JwtUtil 校验令牌有效性,解析 userId 完成身份认证。
2. 注意事项
- Redis:确保
redis-server.exe持续运行,配置与实际环境一致; - 验证码:生产环境禁止返回明文 code,Redis 存储的验证码需及时删除(校验通过后);
- JWT:签名密钥需保密,过期时间不宜过长,可结合刷新令牌机制优化;
- 异常排查:验证码加载失败需检查 Redis 是否启动、配置是否正确;JWT 校验失败需检查签名密钥、令牌是否过期。
