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
})
相关推荐
Bug收容所1 分钟前
Vue+js Day2
前端·javascript·vue.js
aibo8603087 分钟前
基于 Spring Boot 的茶铺管理系统设计与实现
java·spring boot·后端
Thomas.Sir42 分钟前
第4课:配置文件详解:application.yml/properties,多环境配置、配置分组、配置校验
java·spring boot
honkun62 小时前
vue 下拉树组件 vxe-table-select 实现分页多选
前端·javascript·vue.js
杨运交3 小时前
082-缓存模块-基于 Redis Lua 脚本实现分布式锁与原子操作实战
spring boot
aibo8603083 小时前
基于 Spring Boot + Vue3 的博物馆藏品管理系统设计与实现
java·spring boot·后端
zzu123zsw4 小时前
把条件校验收敛到枚举接口:Spring Boot 统一断言模式与零污染异常切面工程化
java·spring boot·后端·架构设计
溪语流沙4 小时前
【Web全栈进阶】监控与告警:线上系统的“体检报告”
前端·vue.js·python·fastapi
code_slave(码畜)4 小时前
微服务架构落地:分库分表实战(下) —— 分布式主键、跨分片查询与分页聚合防坑
数据库·spring boot·分布式·spring cloud·微服务·架构·分库分表
zzu123zsw5 小时前
面对多 RPC 扇入超时崩溃:深入 asyncTool 核心 DAG 编排与线程池隔离防护
java·网络·spring boot·网络协议·rpc·并发编程