完成邮件发送验证码部分

1.开启SMTP服务(以qq邮箱为例)

(1).设置—>账号—>开启服务,如下图所示

(2).点击管理服务—>安全设置最下面—>生成授权码(代码中有效)

2.后端代码部分(后端使用的是express)

(1).先安装nodemailer(我使用的是6.7.0版本)

npm i nodemailer@6.7.0

(2).schma.js

// 邮箱的验证规则

const email = joi.string().email().required().error(new Error("请输入正确规则的邮箱账号"))

//发送邮箱的验证规则对象

exports.reg_sendcode_schema = {

body: {

email,

},

}

(3).router.js

//2.导入需要的验证规则对象

const {reg_sendcode_schema} = require('../schema/user')

//发送邮箱

router.post('/email',expressJoi(reg_sendcode_schema),user_handler.email)

(4).router_handler.js

//发送验证码

exports.email = (req, res) => {

const email = req.body.email;

const checkEmailSql = 'SELECT * FROM users WHERE email = ?';

db.query(checkEmailSql, [email], (err, results) => {

if (err) {

return res.cc(err);

}

if (results.length > 0) {

return res.cc('邮箱已被注册!');

}

// 每次发送前清除之前保存的验证码(用户可以多次点击发送验证码)

const clearCodeSql = "UPDATE users SET code = NULL WHERE email = '你的邮箱' ";

db.query(clearCodeSql, (err, results) => {

if (err) return res.cc(err);

let transporter = nodemailer.createTransport({

service: 'qq', //邮箱类型

secure: true, //是否使用安全连接,对https协议的

port: 465, //qq邮件服务所占用的端口

auth: {

user: "你的邮箱", //开启SMTP的邮箱,发件人

pass: "你生成的授权码" //qq授权码

},

});

//产生随机验证码

var code = "";

for (var i = 0; i < 6; i++) {

code += Math.floor(Math.random() * 10);

}

let options = {

from: "你的邮箱", //发送方

to: req.body.email, //接收方

subject: "激活验证码", //邮件主题

text:"你的验证码:" + code // 邮件正文

};

transporter.sendMail(options, (err, info) => {

if (err) {

res.send(err);

} else {

//加密验证码

code = bcrypt.hashSync(code, 10);

const sendCodeSql = "update users set code=? where email='你的邮箱'";

db.query(sendCodeSql, [code], (err, results) => {

if (err) return res.cc(err);

if (results.affectedRows !== 1) return res.cc("发送验证码失败!");

res.send({

status: 0,

message: "发送验证码成功!",

});

});

}

});

})

})

}

3.前端代码(前端我使用的是Vue3+element-plus)

(1).邮箱的接口(我使用的是axios发送请求)

//引入axios的实例

import axios from '@/http/index.js'

//邮箱的接口

export const sendcode = data => {

const {

email,

} = data

return instance({

url: '/api/email',

method: 'POST',

data: {

email,

}

})

}

(2).注册页面(这里的ElMessage是element-plus内置的弹窗提示)

//html部分

发送验证码

import { ElMessage } from 'element-plus'

//js部分

//注册表单数据(:formData是ts定义的接口,做类型判断)

const registerData: formData = reactive({

username: '',

email: '',

password: '',

repassword: '',

code: null

})

const validateEmail = (value) => {

let reg = /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,5}$/;

return reg.test(value)

}

//发送邮箱

const sendCode = async () => {

const email = registerData.email;

const res = await sendcode(registerData);

if (validateEmail(email)) {

//发送验证码成功

if (res.data.status == 0) {

//后端返回成功的值

ElMessage.success(res.data.message);

} else {

//后端返回失败的值

ElMessage.error(res.data.message);

}

} else {

ElMessage.error('请输入正确的邮箱地址');

}

}

完成注册,验证表单信息

1.验证用户全部的注册信息(下图为我的前端页面)

2.后端代码

(1).schma.js

// 用户名的验证规则

const username = joi.string().alphanum().min(3).max(10).required().error(new Error('用户名为3-10位任意字符'))

// 密码的验证规则

const password = joi.string().pattern(/^[\S]{6,12}$/).required().error(new Error("密码为6-12位任意字符"))

// 邮箱的验证规则

const email = joi.string().email().required().error(new Error("请输入正确规则的邮箱账号"))

//验证码的验证规则

const code = joi.string().regex(/^\d{6}$/).required().error(new Error("请输入六位数字的验证码"));

// 注册表单的验证规则对象

exports.reg_register_schema = {

// 表示需要对 req.body 中的数据进行验证

body: {

username,

password,

email,

code,

},

}

(2).router.js

//导入需要的验证规则对象

const {reg_register_schema} = require('../schema/user')

//注册新用户

router.post('/register',expressJoi(reg_register_schema),user_handler.register)

(3).router_handler.js

//注册新用户的处理函数

exports.register = (req, res) => {

//获取客户端提交到服务器的用户信息

const userInfo = req.body

//定义SQL语句,查询用户名是否被占用

const sqlStr = 'select * from users where username=? OR email=?'

db.query(sqlStr, [userInfo.username, userInfo.email], (err, results) => {

//执行SQL语句失败

if (err) {

return res.cc(err)

}

//判断用户名和邮箱是否被占用

if (results.length > 0) {

for (let i = 0; i < results.length; i++) {

if (results[i].username === userInfo.username) {

return res.cc('用户名已被占用,请更换其他用户名!');

}

if (results[i].email === userInfo.email) {

return res.cc('邮箱已被注册!');

}

}

}

//验证验证码

const checkcodeSql = "select code from users where email='你的邮箱'";

db.query(checkcodeSql, (err, results) => {

if (err) {

return res.cc(err);

}

if (results.length === 0) {

return res.cc("用户查找失败!");

}

const code = results[0].code;

if (!code) {

return res.cc("未发送验证码!");

}

const compareResult = bcrypt.compareSync(req.body.code, results[0].code);

if (!compareResult) {

return res.cc("验证码错误!");

} else {

// 若验证码正确之后,需要将数据库中的验证码清除

const clearcodedSql = "update users set code=null where email='你的邮箱'"

db.query(clearcodedSql, (err, results) => {

console.log(results)

if (err) {

return res.cc(err);

}

if (results.affectedRows !== 1) {

return res.cc("验证码清除失败!");

}

//调用bcrypt.hashSync()对密码进行加密

userInfo.password = bcrypt.hashSync(userInfo.password, 10)

//定义插入新用户的sql语句

const sql = 'insert into users set ?'

//注册身份

const identity = '用户'

//创建时间

const create_time = new Date()

db.query(sql, {

username: userInfo.username,

password: userInfo.password,

email: userInfo.email,

//身份

identity,

//创建时间

create_time,

//初始没冻结

status: 0,

},

function (err, results) {

// 执行 SQL 语句失败

// if (err) return res.send({ status: 1, message: err.message })

if (err) {

return res.cc(err)

}

// SQL 语句执行成功,但影响行数不为 1

if (results.affectedRows !== 1) {

// return res.send({ status: 1, message: '注册用户失败,请稍后再试!' })

return res.cc('注册用户失败,请稍后再试!')

}

// // 注册用户成功

return res.cc('注册成功!', 0)

})

})

}

})

})

}

3.前端代码

(1).用户注册的接口

//注册的接口

export const register = data => {

const {

username,

password,

email,

code,

} = data

return instance({

url: '/api/register',

method: 'POST',

data: {

username,

password,

email,

code

}

})

}

(2).前端页面

//html部分

注册

//js部分

//注册表单数据(:fromData是ts的定义的接口)

const registerData: formData = reactive({

username: '',

email: '',

password: '',

repassword: '',

code: null

})

//注册

const Register = async () => {

const res = await register(registerData)

if (registerData.password == registerData.repassword) {

if (res.data.status == 0) {

ElMessage({

message: res.data.message,

type: 'success'

})

//切换到登录

activeName.value = 'first'

// 清空registerData对象数据

for (let key in registerData) {

registerData[key] = null;

}

} else {

ElMessage.error(res.data.message)

}

} else {

ElMessage.error('两次密码输入不正确')

}

}

总结:

后端保存code的值是拿管理员的定义了一个code字段保存的,然后做清空添加的操作,虽然我做了很多判断处理,但感觉这个方法还是不行,可能存在bug,如果有更好的办法,把这个code缓存起来会更好。

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: