开启邮箱的SMTP服务
登录邮箱,进入设置,开启POP3/SMTP服务
按照提示发送短信
验证通过后将会获取授权码 请务必牢记此授权码,当点击确认后将无法再次查看
服务器地址:一般位于开启POP3/SMTP/IMAP页面的底部
实现邮箱发送验证码
依赖包 nodemailer
% npm i nodemailer
added 1 package, and audited 222 packages in 2m
15 packages are looking for funding
run `npm fund` for details
7 vulnerabilities (2 low, 5 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues, run:
npm audit fix --force
Run `npm audit` for details.
建立一个 nodemailer.js文件
在 /node_modules/nodemailer/lib/well-known/services.json 可以查看 host, port, secure 等相关的配置
“Gmail”: {
“aliases”: [“Google Mail”],
“domains”: [“gmail.com”, “googlemail.com”],
“host”: “smtp.gmail.com”,
“port”: 465,
“secure”: true
},
“QQ”: {
“domains”: [“qq.com”],
“host”: “smtp.qq.com”,
“port”: 465,
“secure”: true
},
“126”: {
“host”: “smtp.126.com”,
“port”: 465,
“secure”: true
},
“163”: {
“host”: “smtp.163.com”,
“port”: 465,
“secure”: true
}
nodemailer.js
import nodemailer from 'nodemailer'// 导入 nodemailer
import common from '../utils/common.js'// 生成随机六位数
//创建一个smtp服务器
const config = {
host: 'smtp.126.com', // 邮件地址 一般位于开启POP3/SMTP/IMAP页面的底部
port: 465, // 端口 /node_modules/nodemailer/lib/well-known/services.json 查看相关的配置
secure: true, // 上面获取的 secure
auth: {
user: '自己的邮箱', //邮箱账号
pass: '邮箱的授权码' //邮箱的授权码,开启 stmp 服务显示的授权码
}
}
// 创建一个SMTP客户端对象
const transporter = nodemailer.createTransport(config)
//发送邮件
export default (mailTo) => {
const code = common.randomNum(6) //生成随机验证码
//发送邮件需要的入参
const email = {
from: `"前端开发"<自己的邮箱>`,// 发件人
subject: '测试--邮箱验证码',// 邮箱主题 发送的邮件标题
to: mailTo,//'xxxxxxx@qq.com',// 收件人,这里由post请求传递过来,多个收件人可以使用逗号分隔
// 邮件内容,HTML格式
html: `
<p>您好!</p>
<p>您的验证码是:<strong style="color:orangered;">${code}</strong></p>
<p> ---该验证码5分钟内有效--- </p>
<p>如果不是您本人操作,请无视此邮件</p>
`
}
return new Promise((resolve, reject) => {
transporter.sendMail(email, (error, info) => {
console.log('mail sent:', error);// .response
if(error) {
return resolve ({state:100, message: "验证码发送失败,请稍后重试", data: error.message})
}
console.log('mail sent:', info.response);
resolve ({state:0, message: "验证码发送成功", code})// state: 0, message: "查询成功", data: result
})
})
}
建立一个 common.js 文件
// Math.random() 函数返回一个浮点数,伪随机数在范围从0 到小于1,也就是说,从 0(包括 0)往上,但是不包括 1(排除 1),然后你可以缩放到所需的范围。实现将初始种子选择到随机数生成算法;它不能被用户选择或重置。
// 返回一个在指定值之间的随机数。这个值不小于 min(有可能等于),并且小于(不等于)max。
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min
}
// Math.floor() 函数总是返回小于等于一个给定数字的最大整数。Math.ceil() 静态方法总是向上舍入,并返回大于等于给定数字的最小整数。
// 返回了一个在指定值之间的随机整数。这个值不小于 min (如果 min 不是整数,则不小于 min 的向上取整数),且小于(不等于)max。
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min //不含最大值,含最小值
}
// 得到一个两数之间的随机整数,包括两个数在内
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min //含最大值,含最小值
}
// 得到一个指定位数的整数字符串
function randomNum(num){
// Math.pow() 函数返回基数(base)的指数(exponent)次幂,即 base^exponent。** 可以看做是Math.pow(x , y)的语法糖,其作用与Math.pow()一致
// x ** y 表示:返回 x 的 y 次幂
// padEnd() 方法会将当前字符串从末尾开始填充给定的字符串(如果需要会重复填充),直到达到给定的长度。填充是从当前字符串的末尾开始的。
// padStart() 方法用另一个字符串填充当前字符串(如果需要会重复填充),直到达到给定的长度。填充是从当前字符串的开头开始的。
return String(Math.floor(Math.random() * 10 ** num)).padEnd(6, '0') //生成随机验证码
}
// 导出
export default {
getRandomArbitrary,
getRandomInt,
getRandomIntInclusive,
randomNum,
}
发送验证码的接口
import Joi from 'joi'// 表单校验
import nodemailer from '../../plugins/nodemailer.js'// 邮件验证
// 定义校验规则 电子邮件
const emailSchema = Joi.object({
email: Joi.string()
.email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } })
.messages({'string.email': `请输入正确的邮件地址`}).required(), // 有效的电子邮件地址字符串 必须有两个域部分,例如 example.com TLD必须是.com或.net
})
// 发送验证码的时间及对应验证码
const codeInfo = {}
// 发送验证码的接口
router.post('/email', (req, res) => {
// 校验
const { error } = emailSchema.validate(req.body)// , value email //刚刚从前台传过来的邮箱
// console.log(error)
// 如果验证通过,就只会返回value属性,如果验证错误,就还有一个error对象,其中error对象的message描述了失败原因:
if(error){
return res.output(error)
}
//去数据库中找有没有同名的邮箱,
db.query('select * from AdminUser where email=?', req.body.email, (err, results) => {
// 执行失败
if (err) return res.output(err)
// 执行成功,但邮箱已经注册
if(results && results.length > 0) return res.output('该邮箱已经注册')
nodemailer(req.body.email).then(result => {
// console.log('res - ' + result.state + ' -- ' + result.code)
if(result.state === 0){
codeInfo[req.body.email] = { time: new Date().getTime(), code: result.code }
res.output('发送成功', 0)
}else{
res.output(result.data)
}
})
})
})
注册接口
// 验证码
const info = codeInfo[req.body.email];
// console.log(' -- ', codeInfo, ' -- ', info)
if(!info){
return res.output('验证码错误')
}
const registerTime = new Date().getTime()
if (registerTime - info.time >= 5 *1000 * 60) {// 5分钟内有效
return res.output('验证码已过期')
}
if(req.body.code !== info.code) {
return res.output('验证码错误')
}
delete req.body.code