vue+springboot项目的登录验证码(JAVA自带)

news2024/12/23 4:58:47

后台springboot

CaptureController

package com.example.controller;

import com.example.common.Result;
import com.example.service.AuthCodeService;
import com.example.utils.CodeUtils;
import lombok.SneakyThrows;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/")
public class CaptureController {
    @Autowired
    AuthCodeService service;

    /**
     * 获取验证码文本
     *
     * @return
     */
    @GetMapping("/getCode")
    public Result getAuthCode(HttpServletRequest request) {
        String text = CodeUtils.generateCode();
        service.bandUserAuthCode(request.getSession().getId(), text);
        return Result.success(text);
    }

    @GetMapping("/getImg")
    @SneakyThrows
    public ResponseEntity<byte[]> drawAuthCode(@Param("text") String text) {
        return service.drawAuthCodeImg(text);
    }

    @GetMapping("/verifyCode")
    public Result verifyAuthCode(HttpServletRequest request, @Param("code") String code) {
        // 获取sessionid
        String sessionId = request.getSession().getId();
        boolean isVerificationSuccess = service.authUserCode(sessionId, code);
        System.out.println("验证结果:" + isVerificationSuccess);
        if (isVerificationSuccess) { //true
            return Result.success(); // 返回状态码200表示验证成功
        } else {
            return Result.error(); // 返回状态码500表示验证失败
        }
    }

}

 AuthCodeService

package com.example.service.impl;

import com.example.service.AuthCodeService;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

@Service
public class AuthCodeServiceImpl implements AuthCodeService {

    private String findSession;

    /**
     * 绑定用户验证码
     *
     * @param sessionId sessionId
     * @param authCode  验证码文本
     */
    @Override
    public void bandUserAuthCode(String sessionId, String authCode) {
        authCodeMap.put(sessionId, authCode);
        findSession = authCodeMap.get(sessionId);
    }

    /**
     * 验证用户验证码
     *
     * @param sessionId sessionId
     * @param authCode  验证码文本
     */
    @Override
    public Boolean authUserCode(String sessionId, String authCode) {
        System.out.println("authUserCode: " + authCode);
//        String text = authCodeMap.get(sessionId);
        String text = findSession;
        System.out.println(authCodeMap.get(sessionId));
        System.out.println("text: " + text);
        if (authCode.isEmpty() || !authCode.equals(text)) {//验证码为空或不匹配
            return false;
        }
        // 验证码验证通过,删除验证码
        authCodeMap.remove(sessionId);
        return true;
    }

    /**
     * 绘制验证码图片
     *
     * @param text 文本内容
     * @return
     */
    @Override
    public ResponseEntity<byte[]> drawAuthCodeImg(String text) throws IOException {
        //创建一个115*45的画布
        BufferedImage canvas = new BufferedImage(115, 45, BufferedImage.TYPE_INT_RGB);

        //获取画布打画笔对象
        Graphics g2d = canvas.getGraphics();

        //创建颜色数组,用于绘制随机颜色
        ArrayList<Color> colorList = new ArrayList<>();
        colorList.add(Color.cyan);
        colorList.add(Color.PINK);
        colorList.add(Color.ORANGE);
        colorList.add(Color.green);

        //创建随机数对象
        Random rd = new Random();

        for (int i = 0; i < text.length(); i++) {
            //获取随机颜色索引
            int index = rd.nextInt(colorList.size());
            //设置画笔随机颜色
            g2d.setColor(colorList.get(index));
            //设置字体大小
            g2d.setFont(new Font(null, Font.BOLD, 15));

            //计算随机x坐标
            int xPoint = (i + 1) * 20;

            //计算随机y坐标
            int yPoint = rd.nextInt(canvas.getHeight() / 2) + 15;

            g2d.setFont(new Font(null, Font.BOLD, 25));
            //绘制验证码
            g2d.drawString(String.valueOf(text.charAt(i)), xPoint, yPoint);

            //绘制字母
            g2d.drawString(text.charAt(i) + "", xPoint, yPoint);
        }
        //绘制15条干扰线
        for (int i = 0; i < 15; i++) {
            g2d.setColor(colorList.get(rd.nextInt(colorList.size())));
            g2d.drawLine(rd.nextInt(canvas.getWidth()), rd.nextInt(canvas.getHeight()), rd.nextInt(canvas.getWidth()), rd.nextInt(canvas.getHeight()));
        }
        //将图片转换为输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ImageIO.write(canvas, "png", baos);
        //释放画布资源
        g2d.dispose();

        return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG).body(baos.toByteArray());
    }
}

 AuthCodeService

package com.example.service;

import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


public interface AuthCodeService {

    //用于临时存储用户绑定的验证码
     Map<String, String> authCodeMap = new HashMap<>();

    /**
     * 绑定用户验证码
     * @param sessionId sessionId
     * @param authCode 验证码文本
     */
     void bandUserAuthCode(String sessionId, String authCode);


    /**
     * 验证用户验证码
     * @param sessionId sessionId
     * @param authCode 验证码文本
     */
    Boolean authUserCode(String sessionId, String authCode);

    /**
     * 绘制验证码图片
     * @param text 文本内容
     * @return
     */
    ResponseEntity<byte[]> drawAuthCodeImg(String text) throws IOException;
}

 CodeUtils

package com.example.utils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class CodeUtils {
    /**
     * 生成4位字符验证码
     *
     * @return
     */
    public static String generateCode() {
        //创建字符数组,1-9,A-Z,a-z
        char[] arr = {
                '1', '2', '3', '4', '5', '6', '7', '8', '9', // 数字 1 到 9
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', // 大写字母 A 到 Z
                'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' // 小写字母 a 到 z
        };

        //创建随机数对象
        Random rd = new Random();


        //创建SB对象,用于生成验证码
        StringBuilder sb = new StringBuilder();

        //循环四次,拼接四个字符
        for (int i = 0; i < 4; i++) {
            //获取随机索引
            int index = rd.nextInt(arr.length);

            sb.append(arr[index]);
        }

        //返回创建的验证码
        return sb.toString();
    }
}

前端Vue

templete模块

<el-form-item prop="captcha">
      <div style="display: flex; justify-content: center; align-items: center;">
         <el-input v-model="data.form.captcha" prefix-icon="key" style="margin-right:10px;"
                        placeholder="请输入验证码"></el-input>
         <el-image :src="captchaUrl" @click="fetchCaptchaImage" style="height: 33px; width: 140px;"></el-image>
       </div>
</el-form-item>
   
    

js模块

<script setup>
import {reactive, ref, onMounted} from "vue";
import {ElMessage} from "element-plus";
import router from "../router";
import request from "@/utils/request";

const data = reactive({
  form: {
    captcha: '',
  }
});

const captchaUrl = ref('');

// 获取验证码图片
const fetchCaptchaImage = () => {
  request.get('http://127.0.0.1:9090/getCode')
      .then(res => {
        if (res.code === '200') {
          captchaUrl.value = `http://127.0.0.1:9090/getImg?text=${res.data}`;
          // 不需要将data.form.captcha设置为空字符串

        } else {
          handleCaptchaError('获取验证码图片失败');
        }
      })
      .catch(error => {
        handleCaptchaError('获取验证码图片时发生网络错误');
      });
};

// 验证验证码
const verifyCaptcha = (captcha) => {
  return new Promise((resolve, reject) => {
    if (!captcha) {
      reject('验证码不能为空');
    } else {
      console.log(captcha);
      request.get(`http://127.0.0.1:9090/verifyCode?code=${captcha}`)
          .then(res => {
            if (res.code === '200') {
              ElMessage.success('验证码匹配成功');
              resolve(); // 验证码匹配成功,执行 resolve 表示验证成功
            } else {
              console.log(res.code);
              console.log(captcha);
              ElMessage.error('验证码错误,请重新输入');
              reject('验证码错误'); // 验证码错误,执行 reject 表示验证失败
            }
          })
    }
  });
};

// 刷新验证码
const refreshCaptcha = () => {
  fetchCaptchaImage();
};

const executeLogin = () => {
  formRef.value.validate((valid) => {
    if (valid) {
      request.post('/login', data.form).then(res => {
        if (res.code === '200') {
          // 登录成功,保存用户信息到 localStorage
          localStorage.setItem('student-user', JSON.stringify(res.data));
          ElMessage.success('登录成功');
          router.push('/home'); // 跳转到主页
        } else {
          ElMessage.error(res.msg);
        }
      });
    }
  });
};

const login = async () => {
  try {
    await formRef.value.validate(); // 首先验证用户名和密码
    await verifyCaptcha(data.form.captcha); // 等待验证码验证
    // 验证码验证成功,执行登录
    executeLogin();
  } catch (error) {
    console.error('登录失败:', error);
  }
};

// 组件加载时刷新验证码
onMounted(refreshCaptcha);

</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1625129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ELF 1技术贴|CAN接口浅析:从原理到对测

引言 在当今智能化、网络化的时代&#xff0c;各种电子设备间的高效通信成为了技术发展的关键。而控制器局域网络&#xff08;Controller Area Network&#xff0c;简称CAN&#xff09;&#xff0c;作为嵌入式系统中不可或缺的通信协议&#xff0c;正扮演着链接桥梁的重要角色…

大厂常见算法50题-用两个栈实现队列

专栏持续更新50道算法题&#xff0c;都是大厂高频算法题&#xff0c;建议关注, 一起巧‘背’算法! 文章目录 题目解法总结 题目 解法 先搞清队列与栈的特点&#xff1a;队列先进先出&#xff0c;栈先进后出两个栈的分工&#xff1a;栈A入数据&#xff0c;栈B出数据需要保证取数…

COOIS 生产订单显示系统增强

需求说明&#xff1a;订单系统显示页面新增批量打印功能 增强点&#xff1a;CL_COIS_DISP_LIST_NAVIGATION -->TOOLBAR方法中新增隐式增强添加自定义打印按钮 增强点&#xff1a;BADI-->WORKORDER_INFOSYSTEM新增增强实施 实现位置&#xff1a;IF_EX_WORKORDER_INFOSYS…

【Leetcode】377. 组合总和 Ⅳ

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个由 不同 整数组成的数组 n u m s nums nums&#xff0c;和一个目标整数 t a r g e t target target 。请你从 n u m s nums nums 中找出并返回总和为 t a r g e t targ…

【STM32+HAL+Proteus】系列学习教程---ADC(查询、中断、DMA模式下的电压采集)

实现目标 1、学会STM32CubeMX软件关于ADC的配置 2、掌握ADC三种模式&#xff08;查询、中断、DMA&#xff09;编程 3、具体目标&#xff1a;1、将开发板单片机采集到的电压值上传至上位机串口调试助手显示。 一、ADC 概述 1、什么是ADC? ADC&#xff08;Analog to Digit…

实验一: 设备密码配置与远程管理

1.实验环境 用路由器和交换机搭建实验环境 2.需求描述 实现管理员主机对交换机和路由器的远程管理 设备上配置的密码都要被加密 3.推荐步骤 对路由器配置的步骤如下&#xff1a; 实现路由器和PC的连通性配置VTY密码和特权模式密码在PC上Telnet 到路由器。 对交换机配置的…

智慧文旅:引领旅游产业智慧升级的创新模式

一、智慧文旅是什么&#xff1f; 智慧文旅是指以当地特色文化为核心&#xff0c;借助现代科技手段&#xff0c;实现旅游景区全面智慧升级的旅游模式。在智慧文旅中&#xff0c;新一代信息网络技术和装备得到充分运用&#xff0c;文化旅游基础设施得到新建和改善&#xff0c;特…

无源DWDM与有源DWDM:两种系统在5G时代的作用与挑战

随着互联网、大数据和云计算等技术的快速发展&#xff0c;光纤通信技术在现代通信领域扮演着越来越重要的角色。作为光纤通信的关键技术之一&#xff0c;波分复用&#xff08;DWDM&#xff09;技术在提高光纤传输容量、优化网络结构等方面具有重要意义。根据系统是否需要外部能…

Ubuntu关闭防火墙、关闭selinux、关闭swap

关闭防火墙 打开终端&#xff0c;然后输入如下命令&#xff0c;查看防火墙状态&#xff1a; sudo ufw status 开启防火墙命令如下&#xff1a; sudo ufw enable 关闭防火墙命令如下&#xff1a; sudo ufw disable 关闭selinux setenforce 0 && sed -i s/SELINUXe…

在windows上安装MySQL数据库全过程

1.首先在MySQL的官网找到其安装包 在下图中点击MySQL Community(gpl) 找到MySQL Community Server 选择版本进行安装包的下载 2.安装包&#xff08;Windows (x86, 64-bit), MSI Installer&#xff09;安装步骤 继续点击下一步 继续进行下一步&#xff0c;直到出现此界面&#…

ClickHouse 数据类型、表引擎与TTL

文章目录 数据类型注意事项 表引擎1.TinyLog 引擎2.MergeTree 引擎3.ReplacingMergeTree 引擎4.AggregatingMergeTree 引擎5.SummingMergeTree 引擎6.CollapsingMergeTree 引擎7.Distributed 引擎 TTL列级 TTL表级TTL 数据类型 ClickHouse 数据类型Java 数据类型数据范围UInt8…

陆游只爱前妻唐婉,深情大渣男太虐了

陆游和唐婉的感情太好了&#xff0c;经常写诗逗乐。陆游科举考不上&#xff0c;沉迷儿女情长&#xff0c;被母亲拆散。 秦侩当政&#xff0c;就是害死岳飞的那个秦桧。陆游第二次考进士&#xff0c;被秦侩批复“喜论恢复”&#xff0c;没考上。陆游的母亲生气&#xff0c;找个…

CSS详解(二)

接上篇CSS详解&#xff08;一&#xff09;-CSDN博客 1、网页布局本质 网页布局的本质是通过 CSS 将各种 HTML 元素&#xff08;即“盒子”&#xff09;摆放到页面中合适的位置。这包括设置元素的尺寸、位置、边距、填充、对齐方式、浮动等。这些盒子通过 CSS 的各种布局机制进…

【深度学习】StabelDiffusion,Lora训练过程,秋叶包,Linux,SDXL Lora训练

文章目录 一、环境搭建指南二、个性化安装流程三、启动应用四、打开web五、开始训练 19.27服务器 一、环境搭建指南 打造一个高效且友好的开发环境&#xff0c;我们推荐使用以下简洁明了的中文资源&#xff1a; 项目源码获取&#xff1a; 通过以下命令轻松克隆项目及所有子模…

抽象的代理模式1.0版本

前言&#xff1a; 在阅读Spring Security官方文档时&#xff0c;里面设计到了一种设计模式——代理模式Proxy 众里寻她千百度&#xff0c;蓦然回首&#xff0c;那人却在灯火阑珊处 开始 在之前的文章里陈述了一个观点——编程语言和语言没有区别 现看看我们日常生活中的代理…

数据库并发控制思维导图+大纲笔记

思维导图 大纲笔记 多用户数据库系统 定义 允许多个用户同时使用的数据库系统特点 在同一时刻并发运行的事务数可达数百上千个多事务执行方式 事务串行执行交叉并发方式 单处理机系统同时并发方式 多处理机系统事务并发执行带来的问题 产生多个事务同时存取同一数据的情况可能…

时间,空间复杂度讲解——夯实根基

前言&#xff1a;本节内容属于数据结构的入门知识——算法的时间复杂度和空间复杂度。 时间复杂度和空间复杂度的知识点很少&#xff0c; 也很简单。 本节的主要篇幅会放在使用具体例题来分析时间复杂度和空间复杂度。本节内容适合刚刚接触数据结构或者基础有些薄弱的友友们哦。…

Python升级打怪(5)

链式调用:用一个函数的返回值作为另外一个函数参数 嵌套调用:一个函数在另一个函数定义里面&#xff0c;而调用该定义函数既可以使用在其里面的函数 在Pycharm中调试器的左下角能够看到函数之间的"调用栈" 调用栈里面描述了当前这个代码的函数之间&#xff0c;调用…

spring cache(一)介绍

一、介绍 1、背景 项目中使用最多的缓存技术就是Redis,用Redis就可以实现了&#xff0c;为什么需要使用spring cache&#xff1f; 先看下我们使用缓存步骤: &#xff08;1&#xff09;查寻缓存中是否存在数据&#xff0c;如果存在则直接返回结果 &#xff08;2&#xff09…

MySql基础一之【了解MySql与DBeaver操作MySql】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f525; 欢迎来到我的博客 &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️寻至善的主页 文章目录 前言MySQL的基本介绍DBeaver及MYSQL操作 前言 本系列为MySql基础&#xff0c…