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
})
相关推荐
独泪了无痕4 小时前
SpringBoot Event事件机制,轻松实现业务解耦
spring boot·后端·spring
悲且狂5 小时前
SpringBoot项目改造注意事项(旧项目框架复用)
java·spring boot·后端
用户50093768390397 小时前
热敏小票 Web 打印:我在 58/80mm 上折腾的两周
前端·vue.js
SQL-First布道者10 小时前
⚡Spring JDBC 完整体系 · 第 10 集 · 手搓 `BaseCondition`
java·spring boot·后端·spring·mybatis·spring jdbc
2601_9620746810 小时前
Spring Boot的无缝衔接:深入解析与实践
数据库·spring boot·后端
南城以南溫暖如初14711 小时前
社交裂变商城系统设计与实战开发指南
java·spring boot·mysql·vue·mybatis
xiaoqiMikko11 小时前
Spring 官方给 5.3 线开了三个修复版,Maven Central 上一个都没有
java·spring boot
南城以南溫暖如初14711 小时前
分享返现商城系统开发实战:技术架构与运营经验指南
java·spring boot·mysql·架构·vue·mybatis
vipxieliang11 小时前
Java切面编程(AOP)详解:从核心概念到实战应用
java·spring boot
.Hypocritical.12 小时前
SpringBoot 各版本 Profile 多环境配置完整对比(2.x/ 2.4+ / 3.x/4.x
java·spring boot·后端