Springboot和vue前后端交互实现验证码登录
大致的思路就是:
- 前端发送请求到后端生成验证码图片返回给前端token,后端把验证码存在缓存中(key,value),key是token,value是验证码的值
- 前端拿到验证码图片渲染,并把token存在localstorage中,在发送请求前到达携带这个token
- 验证时,请求头中拿到token,再根据token从缓存中拿到验证码,跟前端传来的表单验证码对比
一.验证码实现流程图

二、后端具体实现步骤
2.1添加依赖
<!-- hutool工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.12</version>
</dependency>
<!-- Caffeine缓存 -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
2.2配置缓存
@Configuration
public class CacheConfig {
@Bean
public Cache<String, String> captchaCache() {
return Caffeine.newBuilder()
.expireAfterWrite(2, TimeUnit.MINUTES) // 2分钟过期
.maximumSize(10000)
.build();
}
}
2.3验证码控制器
@RestController
@RequestMapping("/api")
public class CaptchaController {
private static final String SESSION_KEY = "X-Captcha-Token";
@Autowired
private Cache<String, String> captchaCache;
// 生成验证码
@GetMapping("/captcha")
public void generateCaptcha(HttpServletResponse response) {
// 生成验证码
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 40);
String code = lineCaptcha.getCode();
// 生成token并存入缓存
String token = UUID.randomUUID().toString();
captchaCache.put(token, code);
// 设置响应
response.setHeader(SESSION_KEY, token);
response.setContentType("image/png");
response.setHeader("Cache-Control", "no-store, no-cache");
// 输出图片
try {
lineCaptcha.write(response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
// 登录验证
@PostMapping("/login")
public Result login(@RequestBody LoginDTO loginDTO,
@RequestHeader(SESSION_KEY) String token) {
// 验证码校验
String cacheCode = captchaCache.getIfPresent(token);
if (StrUtil.isEmpty(cacheCode)) {
return Result.error("验证码已过期");
}
if (!cacheCode.equalsIgnoreCase(loginDTO.getCaptcha())) {
return Result.error("验证码错误");
}
// 清除验证码
captchaCache.invalidate(token);
// 继续登录流程...
}
}
2.4跨域
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
三.前端实现步骤
3.1验证码组件
<template>
<div class="captcha-wrapper">
<input
v-model="form.captcha"
type="text"
placeholder="请输入验证码"
/>
<img
:src="captchaUrl"
@click="refreshCaptcha"
class="captcha-img"
alt="验证码"
/>
</div>
</template>
<script setup>
const SESSION_KEY = 'X-Captcha-Token'
// 刷新验证码
const refreshCaptcha = async () => {
const response = await fetch('/api/captcha')
const token = response.headers.get(SESSION_KEY)
localStorage.setItem(SESSION_KEY, token)
const blob = await response.blob()
captchaUrl.value = URL.createObjectURL(blob)
}
</script>
3.2axios请求配置
// request.js
import axios from 'axios'
const SESSION_KEY = 'X-Captcha-Token'
const request = axios.create({
baseURL: '/api',
timeout: 5000
})
// 请求拦截器:添加token
request.interceptors.request.use(config => {
const token = localStorage.getItem(SESSION_KEY)
if (token) {
config.headers[SESSION_KEY] = token
}
return config
})
// 响应拦截器:清理token
request.interceptors.response.use(response => {
if (response.config.url === '/api/login' && response.data.code === 200) {
localStorage.removeItem(SESSION_KEY)
}
return response.data
})