Springboot和vue前后端交互实现验证码登录

Springboot和vue前后端交互实现验证码登录

大致的思路就是:

  1. 前端发送请求到后端生成验证码图片返回给前端token,后端把验证码存在缓存中(key,value),key是token,value是验证码的值
  2. 前端拿到验证码图片渲染,并把token存在localstorage中,在发送请求前到达携带这个token
  3. 验证时,请求头中拿到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
})
相关推荐
五阿哥永琪13 分钟前
Spring Boot 中自定义线程池的正确使用姿势:定义、注入与最佳实践
spring boot·后端·python
JIngJaneIL1 小时前
基于java + vue校园快递物流管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js
canonical_entropy1 小时前
Nop入门:增加DSL模型解析器
spring boot·后端·架构
OpenTiny社区3 小时前
2025OpenTiny星光ShowTime!年度贡献者征集启动!
前端·vue.js·低代码
狗哥哥3 小时前
从零到一:打造企业级 Vue 3 高性能表格组件的设计哲学与实践
前端·vue.js·架构
计算机毕设VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue图书借阅管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
undsky_4 小时前
【RuoYi-SpringBoot3-Pro】:接入 AI 对话能力
人工智能·spring boot·后端·ai·ruoyi
褪色的笔记簿4 小时前
在 Vue 项目里管理弹窗组件:用 ref 还是用 props?
前端·vue.js
一只小阿乐4 小时前
前端vue3 web端中实现拖拽功能实现列表排序
前端·vue.js·elementui·vue3·前端拖拽
AAA阿giao4 小时前
从“操纵绳子“到“指挥木偶“:Vue3 Composition API 如何彻底改变前端开发范式
开发语言·前端·javascript·vue.js·前端框架·vue3·compositionapi