利用hutool工具类实现图片验证码
# 利用hutool工具类实现图片验证码
# 一、校验验证码
提示
提供接口将收到调用端传过来的校验码,从session或redis取出验证码,两个验证码都全部转小写,进行无大小写区分匹配校验,返回true/flase 。
利用redis存储时,可以在生成验证码并发送给前端时,
同时发送这个临时的唯一标识符(比如 UUID)
。当用户提交登录请求时,前端除了发送用户名、密码和验证码,还需要发送这个唯一标识符。这样,后端可以使用这个唯一标识符来从 Redis 中找到与之关联的验证码,进行验证
。
# 1. 从 Session
校验
在用户未登录时,Session
存储验证码的方式具有一些局限性和潜在问题:
- Session 与用户绑定:
Session
是基于用户会话的,每个用户都有一个唯一的Session ID
。在未登录状态下,浏览器首次访问应用时,服务器会创建一个Session
并分配一个Session ID
,这个 ID 通常通过 Cookie 保存并发送给客户端。 - 跨请求的 Session 依赖:验证码需要在不同请求之间共享,因此依赖
Session ID
的一致性。只要用户的会话有效,验证码可以一直保存在该Session
中。然而,在分布式系统中,如果没有配置Session
共享机制,用户可能在请求验证码和验证验证码时访问了不同的服务器,导致Session
数据不同步。 - Session 管理复杂性:对于多实例部署的应用,需要确保所有服务器节点能够共享
Session
数据,这通常通过负载均衡的“粘性会话”或Session
集群管理来实现,增加了系统复杂性。
/**
* 校验验证码(Session 存储)
*
* 验证码存储方式:Session
*
* @param request HttpServletRequest,用于获取Session中的验证码
* @param inputCode String,用户输入的验证码
* @return boolean 校验结果,true表示匹配成功,false表示匹配失败
*/
@PostMapping("/verifyCaptcha")
public boolean verifyCaptchaFromSession(HttpServletRequest request, @RequestParam String inputCode) {
// 获取Session中的验证码
String sessionCode = (String) request.getSession().getAttribute("verifyCode");
if (sessionCode == null) {
return false;
}
// 比较验证码(忽略大小写)
return sessionCode.equalsIgnoreCase(inputCode);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2. 从 Redis
校验
Redis 存储验证码在未登录状态下有几个明显优势:
- 分布式支持:Redis 是分布式环境下的天然解决方案,能够跨多个服务器实例共享数据,无论用户请求被分配到哪个实例,都能通过统一的 Redis 查询到验证码。
- 灵活的键管理:在未登录状态下,验证码的存储可以通过生成一个唯一的键(如 UUID)来标识。这个键会作为响应的一部分返回给前端,前端在登录请求时将这个键与用户输入的验证码一起提交。这样,后端就可以通过这个键从 Redis 中获取对应的验证码进行验证。
- 轻量级且独立于用户会话:Redis 不依赖用户的会话机制,这使得验证码的存储更加灵活。在用户会话管理复杂的场景下,Redis 不需要依赖
Session ID
,而是通过传递的唯一键来进行数据匹配。
/**
* 校验验证码(Redis 存储)
*
* 验证码存储方式:Redis
*
* @param captchaKey String,前端传递的验证码唯一标识符
* @param inputCode String,用户输入的验证码
* @return boolean 校验结果,true表示匹配成功,false表示匹配失败
*/
@PostMapping("/verifyCaptchaRedis")
public boolean verifyCaptchaFromRedis(@RequestParam String captchaKey, @RequestParam String inputCode) {
// 从Redis中获取验证码
String redisCode = redisTemplate.opsForValue().get("captcha:" + captchaKey);
if (redisCode == null) {
return false;
}
// 比较验证码(忽略大小写)
return redisCode.equalsIgnoreCase(inputCode);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
重要提示
- Redis 存储:推荐在分布式环境下使用 Redis 来存储验证码,确保所有服务实例能共享同一验证码信息。
- Base64 编码:Base64 图片字符串适合用于前端展示,减少传输复杂度。
- 验证码失效时间:设置合理的验证码失效时间,通常建议在 5-30 分钟之间。
# 二、生成验证码并存储(支持Session和Redis)
提供接口将生成的验证码存入session或redis,将验证码以图片格式或者base64编码串返回给调用端。
# 1. 项目依赖(引入 Hutool 工具类)
在 pom.xml
中引入 Hutool 依赖:
<!-- Hutool工具类依赖 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.12</version>
</dependency>
1
2
3
4
5
6
2
3
4
5
6
# 2. 接口响应体:VerifyCodeResp
这个类用于封装验证码响应的格式,包括验证码的唯一标识符(如 captchaKey
)和验证码图片的 Base64 编码:
@Data
public class VerifyCodeResp implements Serializable {
/**
* Captcha唯一标识符,前端通过此Key与Redis中的验证码匹配
*/
private String captchaKey;
/**
* 验证码图片(Base64编码)
*/
private String captchaImg;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 3. 验证码控制器:VerifyCodeController
控制器类包含了多种生成验证码的方法,支持 Session 和 Redis 两种存储方式,提供多种返回格式(如图片或 Base64 字符串)。
# 3.1 基于 ShearCaptcha
的图片验证码(Session 存储)
@RestController
public class VerifyCodeController {
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 生成验证码并存入Session
*
* 验证码类型:ShearCaptcha(扭曲验证码)
* 存储方式:Session
* 返回格式:JPEG 图片格式,直接输出到响应流
*
* @param request HttpServletRequest,用于操作Session
* @param response HttpServletResponse,用于返回图片数据
* @throws IOException 当图片写入失败时抛出
*/
@GetMapping("/verify")
public void generateCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设置响应格式为图片
response.setContentType("image/jpeg");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 创建扭曲验证码,设置宽150,高40,字符数5,干扰线宽度4
ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(150, 40, 5, 4);
// 将验证码写入响应流
shearCaptcha.write(response.getOutputStream());
// 将验证码文字存入Session
request.getSession().setAttribute("verifyCode", shearCaptcha.getCode());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
关键点:
- 验证码类型:
ShearCaptcha
,验证码字符经过扭曲处理。 - 存储方式:
Session
,验证码存储在服务端的会话中。 - 返回方式:直接以 JPEG 图片格式返回。
# 3.2 基于 LineCaptcha
的图片验证码(Session 存储)
/**
* 生成验证码并存入Session
*
* 验证码类型:LineCaptcha(带干扰线条的验证码)
* 存储方式:Session
* 返回格式:JPEG 图片格式,直接输出到响应流
*
* @param request HttpServletRequest,用于操作Session
* @param response HttpServletResponse,用于返回图片数据
* @throws IOException 当图片写入失败时抛出
*/
@GetMapping("/verifyTwo")
public void generateLineCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 设置响应格式为图片
response.setContentType("image/jpeg");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 创建线条验证码,设置宽150,高40,字符数5,干扰线宽度4
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(150, 40, 5, 4);
// 将验证码写入响应流
ImageIO.write(lineCaptcha.getImage(), "JPEG", response.getOutputStream());
// 将验证码文字存入Session
request.getSession().setAttribute("verifyCode", lineCaptcha.getCode());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
关键点:
- 验证码类型:
LineCaptcha
,验证码带有干扰线条。 - 存储方式:
Session
,和方法一类似。 - 返回方式:以 JPEG 图片格式返回。
# 3.3 基于 ShearCaptcha
的 Base64 字符串验证码(Session 存储)
/**
* 生成验证码并返回Base64编码的字符串
*
* 验证码类型:ShearCaptcha(扭曲验证码)
* 存储方式:Session
* 返回格式:Base64 字符串
*
* @param request HttpServletRequest,用于操作Session
* @return String Base64 编码的图片字符串
*/
@GetMapping("/getVerify")
public String generateBase64Captcha(HttpServletRequest request) {
// 创建扭曲验证码,设置宽150,高40,字符数5,干扰线宽度4
ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(150, 40, 5, 4);
// 将验证码文字存入Session
request.getSession().setAttribute("verifyCode", shearCaptcha.getCode());
// 将图片转换为Base64编码字符串返回
return "data:image/png;base64," + shearCaptcha.getImageBase64();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
关键点:
- 返回方式:Base64 编码的字符串,适合在前端直接展示。
# 3.4 基于 LineCaptcha
的 Base64 字符串验证码(Session 存储)
/**
* 生成验证码并返回Base64编码的字符串
*
* 验证码类型:LineCaptcha(带干扰线条的验证码)
* 存储方式:Session
* 返回格式:Base64 字符串
*
* @param request HttpServletRequest,用于操作Session
* @return String Base64 编码的图片字符串
*/
@GetMapping("/getVerifyTwo")
public String generateLineCaptchaBase64(HttpServletRequest request) {
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(150, 40, 5, 4);
// 将验证码文字存入Session
request.getSession().setAttribute("verifyCode", lineCaptcha.getCode());
// 转换为Base64字符串并返回
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ImageIO.write(lineCaptcha.getImage(), "JPEG", bos);
return "data:image/png;base64," + Base64.getEncoder().encodeToString(bos.toByteArray());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 3.5 基于 ShearCaptcha
的 Base64 字符串验证码(Redis 存储)
/**
* 生成验证码并存入Redis
*
* 验证码类型:ShearCaptcha(扭曲验证码)
* 存储方式:Redis(使用UUID作为唯一标识符)
* 返回格式:Base64 字符串
*
* @return VerifyCodeResp 响应体,包含验证码标识符和图片的Base64字符串
*/
@GetMapping("/getVerifyThree")
public VerifyCodeResp generateRedisCaptcha() {
// 生成UUID作为验证码的唯一标识符
String captchaKey = UUID.randomUUID().toString();
// 创建扭曲验证码,设置宽150,高40,字符数5,干扰线宽度0
ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(150, 40, 5, 0);
// 存入Redis,设置30分钟过期时间
redisTemplate.opsForValue().set("captcha:" + captchaKey, shearCaptcha.getCode(), 30, TimeUnit.MINUTES);
// 构造返回体
VerifyCodeResp verifyCodeResp = new VerifyCodeResp();
verifyCodeResp.setCaptchaKey(captchaKey);
verifyCodeResp.setCaptchaImg("data:image/png;base64," + shearCaptcha.getImageBase64());
return verifyCodeResp;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
关键点:
- 使用 Redis 存储验证码,并通过
UUID
作为唯一标识符,适合分布式环境。 - 返回的
VerifyCodeResp
包含验证码的captchaKey
和 Base64 编码的图片。
# 3.6 基于 LineCaptcha
的 Base64 字符串验证码(Redis 存储)
/**
* 生成验证码并存入Redis
*
* 验证码类型:LineCaptcha(带干扰线条的验证码)
* 存储方式:Redis(使用UUID作为唯一标识符)
* 返回格式:Base64 字符串
*
* @return VerifyCodeResp 响应体,包含验证码标识符和图片的Base
64字符串
*/
@GetMapping("/getVerifyFour")
public VerifyCodeResp generateRedisLineCaptcha() {
// 生成UUID作为验证码的唯一标识符
String captchaKey = UUID.randomUUID().toString();
// 创建线条验证码,设置宽150,高40,字符数5,干扰线宽度4
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(150, 40, 5, 4);
// 存入Redis,设置30分钟过期时间
redisTemplate.opsForValue().set("captcha:" + captchaKey, lineCaptcha.getCode(), 30, TimeUnit.MINUTES);
// 将图片转换为Base64编码字符串返回
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ImageIO.write(lineCaptcha.getImage(), "JPEG", bos);
String base64String = Base64.getEncoder().encodeToString(bos.toByteArray());
VerifyCodeResp verifyCodeResp = new VerifyCodeResp();
verifyCodeResp.setCaptchaKey(captchaKey);
verifyCodeResp.setCaptchaImg("data:image/png;base64," + base64String);
return verifyCodeResp;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 三、springboot+vue实现验证码
# 1. 前端验证码输入界面
在前端部分,通过 Vue 和 Element UI 进行表单开发,实现验证码输入功能。
<template>
<div>
<!-- 登录界面容器 -->
<div
style="width: 400px; height: 400px; margin: 150px auto; background-color:rgba(107,149,224,0.5); border-radius: 10px"
>
<!-- 登录标题 -->
<div
style="width: 100%; height: 100px; font-size: 30px; line-height: 100px; text-align: center; color: #4a5ed0"
>
欢迎登录
</div>
<!-- 登录表单 -->
<div style="margin-top: 25px; text-align: center; height: 320px;">
<el-form :model="admin">
<!-- 用户名输入框 -->
<el-form-item>
<el-input
v-model="admin.name"
prefix-icon="el-icon-user"
style="width: 80%"
placeholder="请输入用户名"
></el-input>
</el-form-item>
<!-- 密码输入框 -->
<el-form-item>
<el-input
v-model="admin.password"
show-password
prefix-icon="el-icon-lock"
style="width: 80%"
placeholder="请输入密码"
></el-input>
</el-form-item>
<!-- 验证码输入框与验证码图片 -->
<el-form-item>
<div style="display: flex; justify-content: center">
<el-input
v-model="admin.vercode"
prefix-icon="el-icon-user"
style="width: 42%; margin-right: 10px"
placeholder="请输入验证码"
></el-input>
<!-- 点击验证码图片进行刷新 -->
<img :src="imgUrl" width="140px" height="33px" alt="" @click="refresh()" />
</div>
</el-form-item>
<!-- 登录与注册按钮 -->
<el-form-item>
<el-button
style="width: 80%; margin-top: 10px"
type="primary"
@click="login()"
>登录</el-button
>
<el-button
style="width: 80%; margin-top: 10px; margin-right: 10px"
type="primary"
@click="register()"
>前往注册</el-button
>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import request from "@/utils/request";
export default {
data() {
return {
admin: {}, // 表单数据对象
imgUrl: '' // 验证码图片的URL
};
},
created() {
// 页面加载时,自动刷新验证码
this.refresh();
},
methods: {
// 登录方法,发起登录请求
login() {
request.post("/admin/login", this.admin).then((res) => {
if (res.code === "0") {
// 登录成功处理
this.$message.success("登录成功");
localStorage.setItem("user", JSON.stringify(res.data));
this.$router.push("/home");
} else {
// 登录失败处理
this.$message.error(res.msg);
this.refresh();
this.admin.vercode = ""; // 清空验证码输入框
}
});
},
// 跳转到注册页面
register() {
this.$router.push("/register");
},
// 刷新验证码方法
refresh() {
request.post("/admin/code").then((res) => {
if (res.code === "0") {
// 更新验证码图片与唯一标识符
this.imgUrl = res.data.captchaImg;
// 将后端返回的该图片验证码的唯一key存进当前表单里面,用于提交到后端去获取redis里面的验证码
this.admin.captchaKey = res.data.captchaKey;
}
});
}
}
};
</script>
<style scoped>
/* 可以在此处编写组件的样式 */
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
关键点:
- 通过
v-model
实现表单数据的双向绑定。 - 验证码图片点击后刷新,重新获取验证码。
- 登录请求中将用户名、密码和验证码一起提交,确保输入完整。
# 2. Axios 封装:request.js
在前端通过 Axios 进行 HTTP 请求,包含请求和响应的拦截器,便于统一处理。
import axios from "axios";
import router from "@/router";
// 创建axios实例,设置基础配置
const request = axios.create({
baseURL: "http://localhost:8082/api", // 后端服务的基础路径
timeout: 10000 // 请求超时时间
});
// request 拦截器:发送请求前进行处理,如统一设置 token
request.interceptors.request.use(
(config) => {
// 设置请求头类型
config.headers["Content-Type"] = "application/json;charset=utf-8";
// 从本地存储中获取 token 并添加到请求头中
const user = localStorage.getItem("user");
if (user) {
config.headers["token"] = JSON.parse(user).token;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// response 拦截器:响应后统一处理,如错误处理或数据解析
request.interceptors.response.use(
(response) => {
let res = response.data;
// 如果后端返回的是字符串数据,进行 JSON 解析
if (typeof res === "string") {
res = res ? JSON.parse(res) : res;
}
return res;
},
(error) => {
console.error("Error:", error); // 错误日志
if (error && error.code === "401") {
// 如果错误码为401,跳转到登录页面
router.push("/login");
}
return Promise.reject(error);
}
);
export default request;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
关键点:
request
拦截器中自动添加 token 以实现用户身份验证。response
拦截器中统一处理后端返回数据,确保格式一致。
# 3. 验证码接口:Spring Boot 实现验证码生成与存储
在后端通过 Spring Boot 提供验证码生成接口,使用 Hutool 工具库生成带有干扰线的验证码,并将验证码存储在 Redis 中。
@RestController
@RequestMapping("/admin")
public class VerifyCodeController {
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 获取图片验证码和唯一标识符
*
* @return Result 封装了验证码图片的Base64字符串与唯一标识符
* @throws IOException 当生成图片验证码失败时抛出异常
*/
@PostMapping("/code")
public Result getImageCode() throws IOException {
// 使用 Hutool 创建圆形干扰线验证码,宽100像素,高40像素,字符数4,干扰线数5
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(100, 40, 4, 5);
String code = captcha.getCode(); // 获取验证码字符
String captchaKey = UUID.randomUUID().toString(); // 生成唯一标识符
// 将验证码存入 Redis,设置有效期为30分钟
redisTemplate.opsForValue().set("captcha:" + captchaKey, code, 30L, TimeUnit.MINUTES);
// 将图片转换为Base64编码字符串
String base64String = "data:image/png;base64," + captcha.getImageBase64();
// 封装响应数据
VerifyCodeResp verifyCodeResp = new VerifyCodeResp();
verifyCodeResp.setCaptchaKey(captchaKey);
verifyCodeResp.setCaptchaImg(base64String);
// 返回成功响应
return Result.success(verifyCodeResp);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
关键点:
- 生成的验证码使用
CircleCaptcha
,支持圆形干扰线。 - 验证码存储在 Redis 中,使用 UUID 作为键,确保唯一性。
- 将验证码图片转换为 Base64 字符串,便于前端展示。
# 4. 登录接口:验证用户名、密码及验证码
在后端登录接口中验证用户名、密码和验证码的正确性,支持 Redis 验证。
@RestController
@RequestMapping("/admin")
public class LoginController {
@Resource
private RedisTemplate<String, String> redisTemplate;
@Resource
private AdminService adminService;
/**
* 登录接口
*
* @param admin 前端传递的用户登录信息,包括用户名、密码、验证码等
* @return Result 登录结果,包括用户信息和token
*/
@PostMapping("/login")
@AutoLog("登录该系统") // 自动日志记录
public Result login(@RequestBody Admin admin) {
// 校验用户名和密码是否为空
if (admin.getName() == null || "".equals(admin.getName())) {
throw new CustomException("用户名不能为空!");
}
if (admin.getPassword() == null || "".equals(admin.getPassword())) {
throw new CustomException("密码不能为空!");
}
// 根据用户名查找用户信息
Admin
user = adminService.searchByName(admin.getName());
if (user == null) {
throw new CustomException("用户名或者密码错误!");
}
if (!user.getPassword().equals(admin.getPassword())) {
throw new CustomException("用户名或者密码错误!");
}
// 从 Redis 中获取验证码并进行校验
String redisCode = redisTemplate.opsForValue().get("captcha:" + admin.getCaptchaKey());
if (redisCode == null || !admin.getVercode().equalsIgnoreCase(redisCode)) {
throw new CustomException("验证码错误,请重新输入");
}
// 生成登录 token 并返回
String token = JwtTokenUtils.genToken(String.valueOf(user.getId()), user.getPassword());
user.setToken(token);
user.setPassword(""); // 隐藏密码
return Result.success(user);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
关键点:
- 先校验用户名和密码,再校验验证码,确保完整的登录流程。
- 验证码校验忽略大小写,使用 Redis 进行存储与验证。
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08