Vue3问题:如何实现拼图验证+邮箱登录功能?前后端!

news2024/11/24 17:41:43

前端功能问题系列文章,点击上方合集↑

序言

大家好,我是大澈!

本文约3500+字,整篇阅读大约需要5分钟。

本文主要内容分三部分,第一部分是需求分析,第二部分是实现步骤,第三部分是问题详解。

如果您只需要解决问题,请阅读第一、二部分即可。

如果您有更多时间,进一步学习问题相关知识点,请阅读至第三部分。

1. 需求分析

在登录页面,输入邮箱,点击发送验证码,此时会弹出拼图验证。

用户向右滑动滑块,到达指定缺口位置,就会验证成功。若验证失败,则会刷新拼图,需要重新滑动。

当拼图验证成功后,发送验证码按钮就会显示数字倒计时效果,然后此时会在对应邮箱收到验证码。

在正确输入邮箱验证码之后,点击登录按钮,正确认证并登录成功。

挺常用、也挺有趣的一个功能需求。

图片

2. 实现步骤

2.1 实现前的一些说明

本次需求大致分为部分:点击发送验证码按钮时的拼图验证、常用的邮箱验证码发送。

实现的话,我们会从前端、后端两方面入手,然后给出具体代码实例。

拼图验证在前端实现,利用了vue3-slide-verify库。

邮箱验证码发送在后端实现,利用了Spring框架中的JavaMailSender类,然后邮件发送服务使用的是QQ邮箱。

关于QQ邮箱,在编写后端接口前,一定要记得提前做一些配置

  • 先在QQ邮箱首页-设置-账号-服务中,把服务全部开启。

  • 然后再扫码登录,获取授权码,一定要把这个授权码保存好,不然后面后端接口没法写了。

图片

话不多说,开搞朋友们!

2.2 编写前端代码

先安装功能依赖:

npm install --save vue3-slide-verify

再看模版代码,分为两部分:一个是表单部分,一个是拼图弹框部分。

在表单部分中,给发送验证码按钮一个点击事件,点击让拼图弹框显示。然后禁用此按钮,同时countdown变量开始倒计时递减变化。

在拼图弹框部分中,主要是定义了两个事件函数。fail是操作失败的回调,success是操作成功的回调。再就是slider-text中,定义的是滑块中显示的文字提示。

模版代码:

<template>
  <div class="box">
    <!--表单部分-->
    <el-form :model="dataForm" label-width="120px">
      <el-form-item label="邮箱:">
        <el-input v-model="dataForm.email" />
      </el-form-item>
      <el-form-item label="验证码:">
        <el-input v-model="dataForm.code" />
        <el-button type="warning" @click="visible = true" :disabled="isSendingCode || countdown > 0">
          {{ countdown > 0 ? `重新发送(${countdown})` : '发送验证码' }}
        </el-button>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit" >登录</el-button>
      </el-form-item>
    </el-form>

    <!--拼图部分-->
    <el-card v-if="visible">
      <slide-verify
          ref="slide"
          slider-text="向右滑动->"
          :imgs="images"
          @success="onSuccess"
          @fail="onFail"
          style="margin: auto;"
      ></slide-verify>
    </el-card>
  </div>
</template>

再看逻辑代码,主要分为两部分:一个是拼图验证成功和失败的回调,一个是调用了发送邮箱验证码和认证登录这两个接口。

最先做的,是先引入拼图依赖的对象和样式。

拼图验证成功后,在里面去调用发送邮箱验证码的接口。

按钮倒计时效果,以及发送邮箱验证码、认证登录这两个接口的调用,此处不再赘述,可参考之前如何实现短信验证登录的那篇文章。

再就是,拼图的图片资源数组,可为空。如果数组为空,则会自动下载使用随机网络图片。

逻辑代码:

<script setup>
import {reactive, ref} from 'vue'
import Axios from '../api/axios';
import {ElMessage} from "element-plus";
// 引入依赖对象
import SlideVerify from "vue3-slide-verify";
// 引入依赖样式
import "vue3-slide-verify/dist/style.css";

const dataForm = reactive({
  // 863074625@qq.com
  email: '863074625@qq.com',
  code: '',
})

// 拼图显示标识
const visible = ref(false);
// 拼图的图片资源 可为空,此时会自动下载使用随机网络图片
const images = reactive([
    'https://t7.baidu.com/it/u=2609096218,1652764947&fm=193&f=GIF',
    'https://t7.baidu.com/it/u=2541348729,1193227634&fm=193&f=GIF',
    'https://t7.baidu.com/it/u=2673836711,2234057813&fm=193&f=GIF',
])

// 拼图验证成功回调
const onSuccess = () => {
  ElMessage.success("验证成功!");
  // 隐藏拼图
  visible.value = false;
  // 拼图验证成功,发送邮箱验证码
  sendVerificationCode();
}

// 拼图验证失败回调
const onFail=()=>{
  ElMessage.error("验证不通过!")
}

// 发送验证码按钮禁用标识
let isSendingCode = ref(false);
// 倒计时变量
let countdown = ref(0);

// 发送验证码,调验证码接口
const sendVerificationCode = () => {
  // 检查邮箱是否有效
  // ...

  // 调发送邮箱接口
  Axios.get('/admin/sendEmail', {
    params: {
      email: dataForm.email,
    }
  })
  .then(res => {
    ElMessage.success(res.data)
  })
  .catch(error => {
    console.error(error);
  });


  isSendingCode.value = true;
  // 设置倒计时时间,这里假设为10秒
  countdown.value = 10;

  // 倒计时效果
  const countdownInterval = setInterval(() => {
    countdown.value--;
    if (countdown.value <= 0) {
      clearInterval(countdownInterval);
      isSendingCode.value = false;
    }
  }, 1000);
}

// 登录,调检验验证码和密码的登录接口
const onSubmit = () => {
  // 调发送邮箱接口
  Axios.post('/admin/checkEmailLogin', {
    email: dataForm.email,
    code: dataForm.code,
  })
  .then(res => {
    ElMessage.success(res.data)
  })
  .catch(error => {
    console.error(error);
  });
}
</script>

关于vue3-slide-verify拼图库的属性和回调详细整理,如果朋友你有空余时间,可见文章第部分。

2.3 编写后端接口

对于后端实现,要先引入邮箱发送依赖,再做一些服务的配置,再编写两个接口,一个是发送邮箱验证码接口,一个是认证登录接口。

Pom.xml中引入依赖代码:

<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 邮件发送pom支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

application.yml中写入QQ邮箱服务的配置,注意邮箱password,用的就是之前保存的授权码

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mall_tiny?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  redis:
    host: localhost # Redis服务器地址
    database: 0 # Redis数据库索引(默认为0)
    port: 6379 # Redis服务器连接端口
    password: # Redis服务器连接密码(默认为空)
    timeout: 3000ms # 连接超时时间(毫秒)

  # 发送邮箱
  mail:
    username: 317994054@qq.com
    # 授权码
    password: axpaqqxaejiecaag
    host: smtp.qq.com

再编写接口Controller层代码:

/**
* 发送邮箱
*/
@ApiOperation(value = "发送邮箱")
@GetMapping("/sendEmail")
public CommonResult<String> toSendEmail(@RequestParam("email") String email){
  String message = adminService.toSendEmail(email);
  return CommonResult.success(message);
}

/**
* 检验邮箱验证码,校验成功后登录
*/
@ApiOperation(value = "检验邮箱验证码,校验成功后登录")
@PostMapping("/checkEmailLogin")
public CommonResult<String> checkEmailLogin(@RequestBody ToCheckEmailLoginDTO toCheckEmailLoginDTO){
  String checkLogin = adminService.checkEmailLogin(toCheckEmailLoginDTO.getEmail(), toCheckEmailLoginDTO.getCode());

  // 省略用户密码加密校验
  // ...

  // 省略JWT认证
  // ...

  return CommonResult.success(checkLogin);
}

再编写接口Service层代码:

在发送邮箱验证码接口业务层中,先生成一个随字符串Code,再调用JavaMailSendersend方法发送验证码,并把验证码存入Redis中。

在认证登录接口业务层中,将前端传过来的验证码与Redis中存的验证码进行比较,校验成功执行下一步登录操作。

@Autowired
JavaMailSender javaMailSender;

/**
* 发送邮箱
*/
@Override
public String toSendEmail(String email) {
  //1.判定验证码是否过期
  String code = redisTemplate.opsForValue().get(email);
  if (!StringUtils.isEmpty(code)){
      return email+":"+"验证码未过期";
  }
  //2.已过期/无验证码 生成验证码
  //随机生成字符串 做验证码
  int toCode = (int) (Math.random() * (50000 - 40000) + 40000);
  code=Integer.toString(toCode);

  // 发送邮箱
  SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
  simpleMailMessage.setSubject("项目登录验证码");
  simpleMailMessage.setText("尊敬的:"+email+"您的注册校验验证码为:" + code + "有效期5分钟");
  simpleMailMessage.setTo(email);
  simpleMailMessage.setFrom("317994054@qq.com");
  javaMailSender.send(simpleMailMessage);

  String toSendMes = "OK";
  if (ComConstants.OK.equals(toSendMes)){
      //redis 中存放 5分钟过期
      redisTemplate.opsForValue().set(email,code,ComConstants.NUM_FIVE, TimeUnit.MINUTES);
      //3.发送短信
      return "邮箱发送成功";
  }
  return "邮箱发送异常";
}

/**
* 检验邮箱验证码,校验成功后登录
*/
@Override
public String checkEmailLogin(String email, String code) {
  //1.redis 验证码校验
  String redisCode = redisTemplate.opsForValue().get(email);
  if (code.equals(redisCode)){
      return "登入成功";
  }
  return "登入失败";
}

3. 问题详解

3.1 拼图库的属性和回调详细整理

关于vue3-slide-verify拼图库的属性说明:

图片

关于vue3-slide-verify拼图库的回调说明:

图片

最后附上,vue3-slide-verify拼图库官方文档地址:https://www.npmjs.com/package/vue3-slide-verify

3.2 关于实现各种验证登录功能的心得

在项目中我们做登录功能时,会用到各种验证码登录、各种机器验证。这些验证的作用都是为了安全,这些验证的实现也都是大同小异。

对于验证码登录,包括但不限于短信验证码、邮箱验证码、图形验证码登录,无论是前端还是后端,实现起来完全就可以是把代码复制粘贴。

所以,这些我都有写文章做整理,方便朋友们大家使用,也方便自己使用。

对于登录表单各种机器验证,包括但不限于拼图验证、选择验证等,前端实现起来更是五花八门。本来这些验证的实现我都想整理的,最后感觉没有必要,因为这些东西,真的是充满着共同点,熟悉了其中一种,其它的类型做起来也只会是得心应手了。

最后的最后,感谢朋友们的支持,感谢朋友们花时间的耐心阅读,谢谢!

结语

建立这个平台的初衷:

  • 打造一个仅包含前端问题的问答平台,让大家高效搜索处理同样问题。

  • 通过不断积累问题,一起练习逻辑思维,并顺便学习相关的知识点。

  • 遇到难题,遇到有共鸣的问题,一起讨论,一起沉淀,一起成长。

感谢关注微信公众号:“程序员大澈”,然后加入问答群,让我们一起解决实现所有BUG!

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

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

相关文章

给女朋友开发个小程序低价点外卖吃还能赚钱

前言 今天又是无聊的一天,逛了下GitHub,发现一个库里面介绍美团饿了吗外卖红包外卖优惠券,先领红包再下单。外卖红包优惠券,cps分成,别人领红包下单,你拿佣金。哇靠,那我岂不是可以省钱还可以赚钱,yyds。。。。想想都美好哈哈哈!!! 回到正题,这个是美团饿了么分销…

esp-01刷固件/下载软件到内部单片机的方法

此文章为转载&#xff0c;非原创 一、准备 需要准备三个东西&#xff1a; 1.esp模块。ESP-01 和 ESP-01s 的引脚及 flash 容量基本完全兼容&#xff0c;只是内部硬件设计粗糙与否的区别&#xff0c;所以理论上都适用。 2.官方固件。此部分可以从安信可官方教程中下载&#xff0…

python之使用深度学习创建自己的表情符号

目录 部署项目1、首先运行train.py训练模型2、接下运行gui.py测试 一、使用 CNN 进行面部情绪识别二、GUI 代码和表情符号映射 在这个深度学习项目中&#xff0c;我们将对人类面部表情进行分类&#xff0c;以过滤和映射相应的表情符号或头像。 数据集&#xff08;面部表情识别&…

提效神器!10%标注数据,比肩全量标注的模型效果!

不知道大家有没有遇到过数据标注成本高、周期长的困扰&#xff0c;有没有那么一种可能&#xff0c;精心标注少量的数据&#xff0c;配合大量的无标注数据&#xff0c;就能达到比肩全量标注的模型精度呢&#xff1f;是的&#xff0c;PaddleX就带来了这样一款提效神器——大模型半…

超级干货!如何挖公益SRC实战/SQL注入

目录 一、信息收集 二、实战演示 三、使用sqlmap进行验证 四、总结 一、信息收集 1.查找带有ID传参的网站&#xff08;可以查找sql注入漏洞&#xff09; inurl:asp idxx 2.查找网站后台&#xff08;多数有登陆框&#xff0c;可以查找弱口令&#xff0c;暴力破解等漏洞&…

第一百七十四回 如何创建扇形渐变背景

文章目录 1. 概念介绍2. 实现方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在 上一章回中介绍了"如何创建线性渐变背景"相关的内容&#xff0c;本章回中将介绍" 如何创建扇形渐变背景"。闲话休提&#xff0c;让我们一起Talk Flutter吧。 …

打开GeoTIFF文件失败:Unknown field with tag

用QGIS输出的数据类型为UInt16的TIFF文件&#xff0c;无法在GIMP中打开。 GIMP消息提示&#xff1a; 调查 用ImageMagick打开TIFF文件&#xff0c;虽然会出现警告&#xff0c;但是最终还是打开了&#xff1a; 在ImageMagick中重新保存后&#xff0c;就可以用GIMP打开了。使用…

Mapstruct 搭配MP分页食用 - 参考自ballcat项目

参考自 ballcat 一键抵达&#xff1a; Gitee GitHub 场景 使用MyBatis Plus的selectPage方法进行分页查询之后&#xff0c;如果需要将Entity对象转换为Vo对象&#xff0c;需要从Page对象中取出集合列表&#xff0c;手动转换成Vo集合列表数据重新放进Page对象中。 取出集合 设置…

使用postman测试

第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1a;添加请求 第四步&#xff1a;填写请求 代码实现自动关联的位置&#xff1a; 为相关联的接口设置环境&#xff1a; 使用设置的环境变量&#xff1a; 参数化实现测试&#xff1a;测试脚本中仅测试数据不一样&#xff…

[答疑]改善系统的性能,用得着业务建模吗

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 第五元素 2023-10-27 22:02 潘老师&#xff0c;请教一个实践中遇到的问题&#xff1a; 假设生产人员使用某个工具处理数据&#xff0c;需要10天时间&#xff1b;现在改进了这个工具…

Java排序算法之堆排序

图解 堆排序是一种常见的排序算法&#xff0c;它借助了堆这种数据结构。堆是一种完全二叉树&#xff0c;它可以分为两种类型&#xff1a;最大堆和最小堆。在最大堆中&#xff0c;每个结点的值都大于等于它的子结点的值&#xff0c;而在最小堆中&#xff0c;每个结点的值都小于等…

SpringSecurity6从入门到上天系列第六篇:解决这个问题为什么在引入SpringSecurity之后所有的请求都需要先做登录认证才可以进行访问呢

文章目录 问题引入 1&#xff1a;问题阐述 2&#xff1a;问题分析 一&#xff1a;从SpringBoot的自动装配 1&#xff1a;SpringBootApplication介绍 2&#xff1a;自动装配的核心方法 3&#xff1a;核心方法的调用路径 4&#xff1a;SpringSecurity核心配置 5&#xf…

PMP备考短期极限上岸攻略!

作为一位通过PMP考试成功上岸的3A人士&#xff0c;下面的文章包含了所有PMP考试的实用知识&#xff0c;是一本适合初学者的PMP备考攻略手册。如果你有意向了解或者报考PMP考试&#xff0c;这篇文章肯定会对你有很大的帮助&#xff01; 对于新手第一个需要知道的就是PMP是什么&…

【python】—— 控制语句和组合数据类型(其一)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

Flume(一)【Flume 概述】

前言 今天实在不知道学点什么好了&#xff0c;早上学了3个多小时的 Flink &#xff0c;整天只学一门技术是很容易丧失兴趣的。那就学点新的东西 Flume&#xff0c;虽然 Kafka 还没学完&#xff0c;但是大数据生态圈的基础组件也基本就剩这倆了。 Flume 概述 生产环境中的数据一…

Sql Prompt 10下载安装图文教程

在操作过程中&#xff0c;请暂时关闭你的防病毒软件&#xff0c;以免其误报导致操作失败。 资源 SQL Prompt 10 https://www.aliyundrive.com/s/QuMWkvE1Sv6 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&…

20 - 欲知JVM调优先了解JVM内存模型

从今天开始&#xff0c;我将和你一起探讨 Java 虚拟机&#xff08;JVM&#xff09;的性能调优。JVM 算是面试中的高频问题了&#xff0c;通常情况下总会有人问到&#xff1a;请你讲解下 JVM 的内存模型&#xff0c;JVM 的性能调优做过吗&#xff1f; 1、为什么 JVM 在 Java 中…

Qt高级--(2)自定义标题栏

自定义标题栏 功能点 1.标题栏中最外层布局器使用水平布局器。 2.导航按钮、工具按钮和窗口功能按钮都是用水平布局器&#xff0c;边距和间隔可根据实际情况设置。 3.编写 QSS 样式&#xff0c;并将样式设置到窗口控件中。 4.实现最小化、最大化和关闭窗口按钮功能。 5.实现鼠…

mysql数据库,sql语句中连接查询,连表查询,内连接,外连接,左外连接,右外连接,inner join、left join、right join,全连接

连表查询 现有多张表&#xff1a;员工表 emp&#xff08;员工编号、姓名、工资、部门号、经理编号&#xff09;、部门表 dept&#xff08;部门号、部门名称、部门位置&#xff09;、工资等级表 salgrade&#xff08;等级、工资下限、工资上限&#xff09; 连接查询&#xff1a;…

ClassLoader

Java /Android 默认ClassLoader是PathClassLoader Android 的 PathClassLoader 和DexClassLoader 都是BaseDexClassLoader的子类 BaseClassLoader是ClassLoader的子类,通过loadClass方法加载,Android将Java的ClassLoader简化了,第二个参数arg2 无效 loadClass 通过 findLoad…