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 {@Beanpublic 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";@Autowiredprivate 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 {@Beanpublic 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"><inputv-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
})