当前位置: 首页 > news >正文

引入QQ邮箱发送验证码进行安全校验

最近想给自己的项目在注册时加点安全校验,本想着使用短信验证码,奈何囊中羞涩只能退而求次改用QQ邮箱验证注册~

一.需求分析

  • 场景:用户输入自己的邮箱,点击获取验证码,后台会发送一封邮件到对应邮箱中。

  • 分析:防止刷爆邮箱,可以限制一分钟内只能获取一次。

    • 前端:期限内禁用button按钮。
    • 后端:存入redis设置过期时间,请求先判断redis中是否有数据。

二.环境准备

(1) 邮箱环境

在QQ邮箱中开启SMTP服务,获取授权码

  1. 网页版:进入邮箱,点击设置中的账户
    在这里插入图片描述

  2. 往下翻可以看到如下服务开关,点击开启
    请添加图片描述

点击开启后会得到一串授权码,后端程序中需要用到。

  1. 可能会要求完成相关安全验证
    在这里插入图片描述

(2) 后端环境

大概率是在web项目中使用到,因此我们创建一个SpringBoot工程

  1. 创建好项目后在pom文件中导入操作邮箱所需jar包
        <!--QQ邮箱验证码所需jar包--><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version></dependency><dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-email</artifactId><version>1.4</version></dependency>
  1. 由于我们需要在spring项目使用redis缓存验证码因此还要导入redis的jar包
   <!--     使用redis缓存验证码时效--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
  1. 在yml文件中配置redis,设置了redis密码记得加上密码配置
spring:redis:# redis数据库索引(默认为0),我们使用索引为3的数据库,避免和其他数据库冲突database: 3# redis服务器地址(默认为localhost)host: localhost# redis端口(默认为6379)port: 6379

三.后端程序

(1) 效果实现

  1. 发送邮箱应该算个工具,因此我们可以在工具类中写入如下代码
package com.example.utils;import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;public class SendMailUtil {/*** 发送邮件代码** @param targetEmail 目标用户邮箱* @param authCode    发送的验证码*/public static void sendEmailCode(String targetEmail, String authCode) {try {// 创建邮箱对象SimpleEmail mail = new SimpleEmail();// 设置发送邮件的服务器mail.setHostName("smtp.qq.com");// "你的邮箱号"+ "上文开启SMTP获得的授权码"mail.setAuthentication("158xxx69@qq.com", "fbsxxxxxsijdj");// 发送邮件 "你的邮箱号"+"发送时用的昵称"mail.setFrom("15xxx69@qq.com", "观止");// 使用安全链接mail.setSSLOnConnect(true);// 接收用户的邮箱mail.addTo(targetEmail);// 邮件的主题(标题)mail.setSubject("注册验证码");// 邮件的内容mail.setMsg("您的验证码为:" + authCode+"(一分钟内有效)");// 发送mail.send();} catch (EmailException e) {e.printStackTrace();}}
}
  1. 编写如下接口
@RestController
public class SendMail {@PostMapping("/getCode")@ResponseBodypublic String mail(@RequestParam("targetEmail") String targetEmail) {// 随机生成六位数验证码String authCode = String.valueOf(new Random().nextInt(899999) + 100000);SendMailUtil.sendEmailCode(targetEmail,authCode);return "ok";}
}
  1. 让我们测试一下接口
GET http://localhost:8080/getCode?targetEmail=35xxxx947@qq.com

可以看到如下效果:
在这里插入图片描述

如此我们初步效果就已经实现啦~

(3) 缓存改进

上述程序我们疯狂发送请求可以一直发送邮箱,这显然不是我们所期待的,接下来我们加入redis来改进一下。

@RestController
public class SendMail {@Resourceprivate RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();/*** @param targetEmail 用户邮箱* @return*/@GetMapping("/getCode")@ResponseBodypublic String mail(@RequestParam("targetEmail") String targetEmail) {// 发送前先看下我们是否已经缓存了验证码String yzm = redisTemplate.opsForValue().get("yzm");// 判断是否存在if (yzm == null){// 生成六位数验证码int authNum = new Random().nextInt(899999) + 100000;String authCode = String.valueOf(authNum);// 不存在,我们发送邮箱给用户SendMailUtil.sendEmailCode(targetEmail, "你的验证码为:" + authCode + "(五分钟内有效)");// 存入redis中,设置有效期为1分钟redisTemplate.opsForValue().set("yzm", authCode, 1, TimeUnit.MINUTES);return "发送成功";}// 存在,直接返回,不再发送邮箱~return "请勿重复发送验证码";}}

如此再次测试,可以发现疯狂点击不再产生效果,成功被拦截,如此安全了许多
在这里插入图片描述

至此我们开始想要的效果便已经在小demo中实现了,接下来可以引入正式自己项目啦

四.前端(补充)

用原生js简单写了一个界面,感兴趣的可以看一看
在这里插入图片描述

代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div><input id="mail" type="text"><button id="getCode">获取验证码</button>
</div>
<script>/*按钮禁用60秒,并显示倒计时*/function disabledButton() {const getCode = document.querySelector("#getCode")getCode.disabled = truelet second = 60;const intervalObj = setInterval(function () {getCode.innerText = "请" + second + "秒后再重试"if (second === 0) {getCode.innerText = "获取验证码"getCode.disabled = falseclearInterval(intervalObj);}second--;}, 1000);}document.querySelector("#getCode").addEventListener('click', function () {const mail = document.querySelector("#mail")let xhr = new XMLHttpRequest();xhr.open("GET", "http://localhost:8080/getCode?targetEmail=" + mail.value, true);xhr.send();xhr.onreadystatechange = function () {if (xhr.readyState === 4) {alert(xhr.response);disabledButton()}}})</script>
</body>
</html>

相关文章:

引入QQ邮箱发送验证码进行安全校验

最近想给自己的项目在注册时加点安全校验&#xff0c;本想着使用短信验证码&#xff0c;奈何囊中羞涩只能退而求次改用QQ邮箱验证注册~ 一.需求分析 场景&#xff1a;用户输入自己的邮箱&#xff0c;点击获取验证码&#xff0c;后台会发送一封邮件到对应邮箱中。 分析&#x…...

【c++】数组

文章目录一维数组定义方式数组名案例案例1&#xff1a;元素逆置案例2&#xff1a;冒泡排序二维数组定义方式数组名案例&#xff1a;考试成绩统计数组特点&#xff1a; 1、每个数据元素放在一块连续的内存空间中&#xff1b; 2、数组中每个数据元素都是相同数据类型&#xff1b;…...

线程池的简单实现:Java线程池初学者必读指南

"作为一名Java开发者&#xff0c;是否曾经遇到过多线程并发的问题&#xff1f;线程数量过多时&#xff0c;会导致资源浪费&#xff0c;应用性能下降&#xff0c;甚至发生线程死锁的情况。那么&#xff0c;有没有一种方法可以有效地管理线程&#xff0c;避免这些问题呢&…...

【C#】[带格式的字符串] 复合格式设置字符串与使用 $ 的字符串内插 | 如何格式化输出字符串

复合格式输出 string name "Fred"; String.Format("Name {0}, hours {1:hh}", name, DateTime.Now);通过指定相同的参数说明符&#xff0c;多个格式项可以引用对象列表中的同一个元素。 例如&#xff0c;通过指定“0x{0:X} {0:E} {0:N}”等复合格式字符…...

Lecture4 反向传播(Back Propagation)

目录 1 问题背景 1.1计算图&#xff08;Computational Graph&#xff09; 1.2 激活函数&#xff08;Activation Function&#xff09;引入 1.3 问题引入 2 反向传播&#xff08;Back Propagation&#xff09; 2.1 为什么要使用反向传播 2.2 前馈运算(Forward Propagation…...

Power BI 筛选器函数---Window实例详解

一、Window函数 语法&#xff1a; Window ( <起始位置>,<起始位置类型>,<结束位置>,<结束位置类型>, [<关系>], [<OrderBy>],[空白],[PartitionBy] ) 含义&#xff1a; 对指定分区&#xff08;PartitioinBy)中的行&#xff08;关系表&…...

基础篇—如何创建css样式表,并集成到html文件中?

CSS 创建 HTML相当于一个页面的结构,CSS相当于页面的装饰,浏览器当读到一个样式表时,浏览器会根据它来格式化 HTML 文档。 如何插入样式表 插入样式表的方法有三种: 外部样式表(External style sheet)内部样式表(Internal style sheet)内联样式(Inline style)1、外…...

WindowsServer服务器系列:部署FTP文件服务

1、点击“开始”菜单&#xff0c;选择“服务器管理器” 2、在接下来弹出页面中选择“添加角色和功能” 3、接下来点击“下一步” 4、接下来选择“基于角色或基于功能的安装”并点击“下一步” 5、选择“从服务器池中选择服务器”并点击“下一步” 6、接下来选中“Web 服务器(II…...

华为OD机试 - 数字加减游戏(Python)| 真题+思路+代码

数字加减游戏 题目 小明在玩一个数字加减游戏,只使用加法或者减法,将一个数字 s 变成数字 t。 每个回合,小明可以用当前的数字加上或减去一个数字。 现在有两种数字可以用来加减,分别为 a,b(a!=b),其中 b 没有使用次数限制。 请问小明最少可以用多少次 a,才能将数字 s …...

【c/c++】c语言的自增操作在不同编译器的差别

示例代码 代码如下&#xff1a; #include <stdio.h>#define product(x) ((x)*(x))int main(void) {int i 3, j, k;j product(i); // (i) * (i)k product(i); // (i) * (i)printf("%d %d\n", j, k); }执行结果 在Ubuntu18.04下通过GCC编译和执行的结果…...

【LeetCode第 332 场周赛】

传送门 文章目录6354. 找出数组的串联值6355. 统计公平数对的数目6356. 子字符串异或查询6357. 最少得分子序列6354. 找出数组的串联值 题目 思路 前后指针 代码 class Solution { public:long long findTheArrayConcVal(vector<int>& nums) {long long res 0;i…...

【蓝桥杯单片机】Keil5中怎么添加STC头文件;从烧录软件中添加显示添加成功后新建工程时依旧找不到

蓝桥杯单片机的芯片型号&#xff1a;IAP15F2K61S2 添加头文件&#xff1a;STC15F2K60S2.H 【1】如何通过烧录软件添加STC头文件&#xff1a; 从ATC-ISP的Keil仿真设置中添加&#xff08;同时自动下载仿真驱动&#xff09;仔细阅读添加说明 KEIL5添加STC芯片库_Initdev的博客-…...

图解浏览器渲染页面详细过程

渲染详细过程 产生渲染任务&#xff0c;开启渲染流程 当浏览器的网络线程收到 HTML 文档后&#xff0c;会产生一个渲染任务&#xff0c;并将其传递给渲染主线程的消息队列。 在事件循环机制的作用下&#xff0c;渲染主线程取出消息队列中的渲染任务&#xff0c;开启渲染流程。…...

多线程面试题开胃菜1(5道)

一.多线程有什么用&#xff1f;1&#xff09;发挥多核CPU 的优势随着工业的进步&#xff0c;现在的笔记本、台式机乃至商用的应用服务器至少也都是双核的&#xff0c;4 核、8 核甚至 16 核的也都不少见&#xff0c;如果是单线程的程序&#xff0c;那么在双核 CPU 上就浪费了 50…...

植物育种中广义遗传力的定义

大家好&#xff0c; 我是邓飞。 今天聊一下广义遗传力的计算方法。 广义遗传力定义 广义遗传力&#xff08;H2H^2H2&#xff09;定义为归因于基因型总体遗传变异的表型变异比例。 通常他包括三个解释&#xff1a;&#xff08;详见我这篇博客的公式推导 回归系数 相关系数 遗…...

西瓜书读书笔记—绪论

文章目录机器学习典型的机器学习过程基本术语归纳偏好机器学习 机器学习&#xff1a;致力于研究如果通过计算的手段&#xff0c;利用经验来改善系统自身的性能 在计算机系统中&#xff0c;“经验” 通常以 “数据” 形式存在&#xff0c;因此&#xff0c;机器学习所研究的主要内…...

ES8——Generator函数的使用

babel工具插件下载&#xff1a;npm i --save babel-polyfill 引入&#xff1a;polyfill.js进行转码&#xff08;es8->es5&#xff09; 介绍 Generator函数用于生成迭代器 function * (){} yeild: 作用同return类似 {const obj function* () {yield "a";yield 12…...

德馨食品冲刺A股上市:计划募资9亿元,林志勇为实际控制人

近日&#xff0c;浙江德馨食品科技股份有限公司&#xff08;下称“德馨食品”或“德馨饮料”&#xff09;预披露更新招股书&#xff0c;准备在上海证券交易所主板上市。据贝多财经了解&#xff0c;德馨食品于2022年7月5日递交上市申请&#xff0c;安信证券为其保荐机构。 本次…...

湿敏电阻的原理,结构,分类与应用总结

🏡《总目录》 0,概述 湿敏电阻是指电阻值随着环境的湿度变化而变化的电阻,本文对其工作原理,结构,分类和应用场景进行总结。 1,工作原理 湿敏电阻是利用湿敏材料制成的,湿敏材料吸收空气中水分时,自身的阻值发生变化。 2,结构 如下图所示,市民电阻包括4个部分构成,…...

千锋教育嵌入式物联网教程之系统编程篇学习-03

目录 进程的终止 exit函数 _exit函数 进程退出清理 进程间的替换 进程间通信 常见通信机制 进程间通信的实质 信号 产生信号的方式 信号的默认处理方式 进程对信号的处理方式 kill函数 进程的终止 使用exit函数对进程进行终止&#xff0c;而return只是结束函数&a…...

升级到https

现在很多站长都会考虑将自己的站点从http升级到https&#xff0c;不仅是基于安全的考虑&#xff0c;有的也是因为第三方平台的限制&#xff0c;如谷歌浏览器会将http站点标记为不安全的站点&#xff0c;微信平台要求接入的微信小程序必须使用https等。 那如何将一个http站点升…...

【C语言】数据结构-二叉树

主页&#xff1a;114514的代码大冒险 qq:2188956112&#xff08;欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ &#xff09; Gitee&#xff1a;庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 引入 我们之前已经学过线性数据结构&#xff0c;今天我们将介绍非线性数据结构----树 树是一种非线性的…...

c++中std::condition_variable最全用法归纳

前言 建议阅读以下文章前需先对建立 std::thread 多线程与std::mutex 锁有一定程度的熟悉 std::thread最全用法归纳 std::mutex最全用法归纳 概括 使用 std::condition_variable 的 wait 会把目前的线程 thread 停下来并且等候事件通知&#xff0c;而在另一个线程中可以使用…...

Python数据可视化:数据关系图表可视化

目录 1、散点图 1.1、趋势显示的二维散点图 1.2、分布显示的二维散点图 1.3、散点曲线图...

Urho3D约定

Urho3D使用以下约定和原则&#xff1a; 左手坐标系。正X、Y和Z轴指向右侧、上方和前方&#xff0c;正旋转为顺时针。度用于角度。顺时针顶点定义正面。音频音量指定为0.0&#xff08;静音&#xff09;到1.0&#xff08;全音量&#xff09;路径名使用斜杠而不是反斜杠。调用操作…...

python数据结构-列表,元组

列表 列表是Python中最通用的数据类型&#xff0c;可以写成方括号之间的逗号分隔值(项目)列表。 使用列表的重要事项是&#xff0c;列表中的项目不必是相同的类型。也就是说一个列表中的项目(元素)可以是数字&#xff0c;字符串&#xff0c;数组&#xff0c;字典等甚至是列表类…...

Properties类读配置文件、修改配置文件

Properties类简介(1)Properties类是专门用于读写配置文件的集合类(2)配置文件的后缀名为.properties,内容格式为:# 可以用“#”作为注释 键值 键值**注意:**键值对不需要有空格,值不需要用引号一起来。默认类型是String。键、值不可以是null(3)Properties类的方法可查找api文档…...

图解LeetCode——剑指 Offer 24. 反转链表

一、题目 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 二、示例 示例: 【输入】 1->2->3->4->5->NULL 【输出】 5->4->3->2->1->NULL 限制&#xff1a; 0 < 节点个数 < 5000 三、…...

【C语言】“指针的运算”、“指针与数组”

文章目录一、指针运算1.指针 - 整数2.指针-指针3.指针关系运算二、指针与数组三、二级指针四、指针数组完结一、指针运算 指针可以进行整数&#xff0c;指针-指针&#xff0c;还有关系运算&#xff0c;其他的运算会被编译器阻止。 1.指针 - 整数 对指针进行的时候一定要注意不…...

Linux高级命令之查找文件命令

查找文件命令学习目标能够说出查找文件使用的命令1. find命令及选项的使用命令说明find在指定目录下查找文件(包括目录)find命令选项:选项说明-name根据文件名(包括目录名)字查找find命令及选项的效果图:2. find命令结合通配符的使用通配符:是一种特殊语句&#xff0c;主要有星…...

网络培训法/seo外链推广工具下载

原标题&#xff1a;一加6T被曝将预装Android P 这一点其它品牌比不了近年来国产手机群雄崛起&#xff0c;不仅在国内获得了很高的呼声&#xff0c;一些品牌在国外也拥有着很高的热度&#xff0c;从以往的三星、苹果手中抢占了很多的份额&#xff0c;如今三星在国内的销量非常惨…...

织梦做英文网站/青岛网络优化代理

输入vim /etc/sysconfig/network-scripts/ifcfg-eth0命令&#xff0c;编辑该文件的信息&#xff1a; DEVICE"eth0" #IPV6INIT"yes" #从dhcp改成static BOOTPROTO"static" UUID"*********" #从no改成yes ONBOOT"yes" #这…...

技术网站推广范例/前端培训哪个机构靠谱

LabVIEW开发150瓦射频发生器 150瓦射频发生器的原型可以在手动模式下独立运行&#xff0c;也可以通过外部数据进行编程采集系统&#xff0c;如NI紧凑型RIO FPGA系统或类似产品&#xff0c;具有更高的灵活性和易用性操作。 独立模式&#xff1a;在150/380KHz&#xff08;固定&a…...

越秀网站建设推广/近期热点新闻

记者今天从上海律师协会了解到&#xff0c;截至2019年底&#xff0c;上海共有1660家律所、26520名律师。 数据还进一步显示了2019年上海律师行业的情况——哪个区的律师最多&#xff1f;律师男女比例如何&#xff1f;律师业务承办量增长了多少……浦东律师数量最多&#xff0c;…...

怎么利用360域名做网站/深圳google推广

刚开始接触vue 的webpage脚手架的时候是不是对那一堆文件夹特别懵。下面我们就来看看脚手架里面的目录都代表什么吧&#xff01;首先安装好脚手架的时候目录是这样的1.node_modues --这个文件夹里面是存放下载好的依赖(模块&#xff0c;组件)--依赖的工具包目录2.public …...

源码之家网站/软文营销的定义

在AngularJs中作用域是非常重要的。 $scope可以嵌套&#xff0c;存在父子作用域&#xff0c;兄弟作用域&#xff0c;那么它们这些作用域相互怎么相互发送信息了。 父子作用域&#xff1a; 看如下代码&#xff1a;&#xff08;在html标签中添加ng-appmyApp) <div ng-contro…...