[!attention] No Reproduction Without Permission
Made By Hanbin Yi
图片验证码登录交互流程
- 前端触发请求:用户操作(如点击 “获取验证码”)时,前端向后端发送验证码请求。
- 后端生成验证码:
- 生成图片验证码(含随机字符)和对应的 “正确答案”;
- 生成唯一标识(如 sessionID),将 “唯一标识 + 验证码答案” 存储到服务端(如 Session)。
- 后端返回数据:把 “验证码图片 + 唯一标识” 返回给前端,前端展示验证码图片。
- 用户提交信息:用户输入账号密码时,同时填写验证码,并携带 “唯一标识” 一起提交登录请求。
- 后端校验验证码:
- 后端通过 “唯一标识” 从 Session 中取出对应的验证码答案;
- 对比用户提交的验证码与答案,校验是否正确。
后端部分
这里需要导入一个生成图像验证码工具类

后端图片验证码生成接口代码
/**
* 验证码控制器
* 专门处理与验证码相关的HTTP请求
*/
@RestController // 标记此类为Spring MVC的控制器,并且所有方法的返回值都会自动转换为JSON格式
@RequestMapping("code") // 定义了此类中所有接口的统一访问前缀。
public class CodeController {
/**
* 生成并返回图片验证码的接口
* @param session HttpSession对象,用于在服务器端存储验证码信息
* @return ResponseDTO 自定义的响应对象,包含状态码、消息和验证码图片数据
*/
@GetMapping() // 表示当前方法处理HTTP的GET请求
public ResponseDTO getCode(HttpSession session) {
// 1. 创建验证码工具类实例
// 假设ValidateCodeUtil是一个自定义的工具类,封装了生成验证码图片和文本的逻辑
ValidateCodeUtil validateCodeUtil = new ValidateCodeUtil();
// 2. 生成验证码图片的Base64编码字符串
// 该方法内部会随机生成验证码文本,并将其绘制成图片,最后编码成Base64格式的字符串
// 这样做的好处是前端可以直接使用<img src="data:image/png;base64,xxx..."/>来显示图片,无需额外请求
String codeImage = validateCodeUtil.getRandomCodeImage();
// 3. 获取与图片对应的验证码文本答案
// 从刚才生成的验证码工具类实例中获取正确的验证码字符串
String code = validateCodeUtil.getCode();
// 4. 生成一个唯一标识UUID
// 这个UUID将作为该验证码在服务器端的“钥匙”,用于后续验证时查找对应的正确答案
// 使用UUID可以确保在分布式环境或多用户并发请求时不会产生冲突
String unique = UUID.randomUUID().toString();
// 5. 将验证码信息存入Session
// 以UUID为key,验证码文本为value,存储在当前用户的HttpSession中
// 这样当用户提交登录表单时,后端就可以通过这个UUID找到之前存储的正确验证码进行比对
session.setAttribute(unique, code);
// 6. 构建返回给前端的数据
// 使用HashMap来组织需要返回的数据
HashMap<String, String> map = new HashMap<>();
map.put("image", codeImage); // 验证码图片的Base64字符串
map.put("unique", unique); // 验证码的唯一标识UUID
// 7. 返回成功响应
// 使用自定义的ResponseDTO封装结果,返回给前端
return ResponseDTO.success(map);
}
- 流程:
- 生成随机验证码文本(如 “A7b9”)和对应的图片(转成 Base64 字符串,方便前端直接显示)。
- 为该验证码生成一个唯一标识(UUID)。
- 将 UUID 和验证码文本存入 Session(服务器端临时存储)。
- 返回 Base64 图片和 UUID 给前端。

uuid

用户登录验证
@Override
public ResponseDTO login(UserVO userVO, HttpSession session) {
// 1. 从 Session 中获取存储的验证码
// - userVO.getUnique() 是前端传来的验证码唯一标识
// - session.getAttribute() 通过该标识获取之前存储的正确验证码
// - .toString() 确保获取到的是字符串类型
String codeSession = session.getAttribute(userVO.getUnique()).toString();
// 2. 校验验证码
// - 先判断用户是否输入了验证码 (userVO.getCode() == null)
// - 再比较用户输入的验证码与 Session 中存储的验证码(不区分大小写)
// - 如果任一条件不满足,返回验证码错误信息
if (userVO.getCode() == null || !userVO.getCode().equalsIgnoreCase(codeSession)) {
return ResponseDTO.fail("验证码错误");
}
// 3. 校验账号和密码
// - 调用 userMapper 的 login 方法,根据用户名和密码查询数据库
// - 如果返回的 userDO 为 null,说明账号或密码不匹配
UserDO userDO = userMapper.login(userVO);
if (userDO == null) {
return ResponseDTO.fail("账号或密码错误");
}
// 4. 登录成功
// - 如果所有校验都通过,返回成功信息和用户数据
return ResponseDTO.success(userDO);
}
- 流程:
- 从前端传入的参数中,获取 UUID 和用户输入的验证码。
- 用 UUID 从 Session 中取出之前存储的正确验证码,与用户输入的验证码比对(不区分大小写)。
- 验证码通过后,再用账号和密码查询数据库,验证身份。
- 所有验证通过则返回成功(带用户信息),否则返回对应错误提示(验证码错误 / 账号密码错误)。
前端部分
<template>
<div>
<!-- 账号输入框 -->
账号<el-input v-model="account" placeholder="请输入账号"></el-input>
<!-- 密码输入框,show-password 属性会显示/隐藏密码 -->
密码<el-input v-model="password" placeholder="请输入密码" show-password></el-input>
<!-- 验证码输入框 -->
验证码<el-input v-model="code" placeholder="请输入验证码"></el-input>
<!-- 验证码图片:
- :src 绑定图片的 Base64 编码字符串
- `data:image/png;base64,${codeImage}` 是 Data URL 格式,
浏览器可以直接解析并显示图片,无需额外请求服务器
- codeImage 是从后端获取的 Base64 字符串
-->
<img :src="`data:image/png;base64,${codeImage}`" alt="验证码" />
<!-- 登录按钮:点击触发 login 方法 -->
<el-button type="primary" @click="login()">登录</el-button>
</div>
</template>
<script>
export default {
data() {
return {
account: '', // 绑定账号输入框
password: '', // 绑定密码输入框
code: '', // 绑定验证码输入框
codeImage: '', // 存储验证码图片的 Base64 字符串
unique: '' // 存储验证码的唯一标识 UUID
}
},
methods: {
// 登录方法
login() {
console.log('账号:', this.account);
// 发送 POST 请求到 /user/login 接口
this.$axios.post('/user/login', {
account: this.account, // 账号
password: this.password, // 密码
code: this.code, // 用户输入的验证码
unique: this.unique // 验证码的唯一标识(从后端获取)
}).then(response => {
// 请求成功回调
console.log('登录成功:', response.data);
// 在这里可以处理登录成功后的逻辑,例如:
// 1. 存储用户信息到 localStorage 或 Vuex
// 2. 跳转到首页或其他页面
// this.$router.push('/home');
}).catch(error => {
// 请求失败回调
console.error('登录失败:', error);
// 在这里可以处理登录失败后的逻辑,例如:
// 1. 显示错误提示信息(如验证码错误、账号密码错误)
// 2. 刷新验证码图片(防止用户输入错误后无法重新获取)
this.getCodeImage();
});
},
// 获取验证码图片
getCodeImage() {
// 发送 GET 请求到 /code 接口
this.$axios.get('/code')
.then(response => {
console.log(response);
// 从响应数据中提取 Base64 图片和 UUID
this.codeImage = response.data.data.image; // 验证码图片的 Base64 字符串
this.unique = response.data.data.unique; // 验证码的唯一标识 UUID
console.log(this.codeImage);
})
.catch(error => {
// 获取验证码失败
console.error('获取验证码失败:', error);
});
}
},
// 组件挂载后执行(相当于页面加载完成后)
mounted() {
// 自动调用 getCodeImage 方法,获取验证码图片并显示
this.getCodeImage();
}
}
</script>
<style></style>
- 加载即获取:页面加载完成后,立即向后端请求验证码图片和其唯一标识(UUID)。
- 展示与存储:将获取到的验证码图片(Base64 格式)显示在页面上,并隐藏存储其 UUID。
- 用户交互:用户输入账号、密码和验证码。
- 提交验证:用户点击登录时,前端将账号、密码、用户输入的验证码文本以及隐藏的 UUID 一同发送给后端。
- 结果处理:接收后端响应,成功则进行页面跳转等操作,失败则提示错误并刷新验证码图片。
1357

被折叠的 条评论
为什么被折叠?



