网站首页 > 技术文章 正文
前端功能问题系列文章,点击上方合集↑
序言
大家好,我是大澈!
本文约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,再调用JavaMailSender的send方法发送验证码,并把验证码存入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!
猜你喜欢
- 2024-10-26 最近别来杭州!怕你不想回去了……
- 2024-10-26 为什么有人不用免费的WPS,偏要花钱用Office?看完这些就知道了
- 2024-10-26 还在苦恼验证码怎么实现?看看这个验证码组件合集,你想要的都有
- 2024-10-26 时间浪费在哪儿?(时间浪费四种情形)
- 2024-10-26 qq账号被冻结了怎么快速解冻手机号换了
- 2024-10-26 RPA实战:“滑动”验证码与按照“语序”点击两类验证码
- 2024-10-26 产品心理学:给予用户理解和宽容(产品的心理功能有( )( )( ))
- 2024-10-26 OPPO Reno4 Pro忘记OPPO帐号密码怎么办?
- 2024-10-26 你知道新买的手机,怎样重新登录微信账号吗?
- 2024-10-26 短信验证码的深度剖析(短信验证码起什么作用)
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)