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
})
相关推荐
却话巴山夜雨时i1 小时前
Java大厂面试:从Spring Boot到微服务的深度剖析
java·spring boot·spring cloud·微服务·分布式事务·大厂面试
希望永不加班1 小时前
SpringBoot 缓存注解:@Cacheable/@CacheEvict 使用
java·spring boot·spring·缓存·mybatis
源码站~1 小时前
基于Spring Boot+Vue3的烹饪交流学习系统 设计与实现
java·vue.js·spring boot·后端·mysql·毕业设计·毕设
zihao_tom1 小时前
Spring Boot 整合 Druid 并开启监控
java·spring boot·后端
小小小米粒1 小时前
原生 JS:数据和视图「分离」,必须手动同步原生 JS 里,数据是数据,视图是视图,两者完全没关系
前端·javascript·vue.js
摸鱼仙人~1 小时前
纯前端 Vue 实现共享预览链接方案
前端·javascript·vue.js
鬼先生_sir1 小时前
SpringBoot-源码剖析
java·spring boot·springboot源码解析
摸鱼仙人~1 小时前
前端开发中“共享预览链接”场景-企业级最简方案:Vue + 极简后端(2 接口 1 张表)
前端·javascript·vue.js
摇滚侠11 小时前
JAVA 项目教程《苍穹外卖-12》,微信小程序项目,前后端分离,从开发到部署
java·开发语言·vue.js·node.js