简介
实现邮箱验证服务
一、使用nodejs实现认证服务
我们的认证服务要给邮箱发送验证码,所以用nodejs较为合适,nodejs是一门IO效率很高而且生态完善的语言,用到发送邮件的库也方便。
nodejs可以去官网下载https://nodejs.org/en,一路安装就可以了
我们新建VarifyServer文件夹,在文件夹内部初始化server要用到的nodejs库的配置文件
右键打开power shell
cpp
npm init
根据提示同意会创建一个package.json文件
接下来安装grpc-js包
cpp
npm install @grpc/grpc-js
接着安装proto-loader用来动态解析proto文件
cpp
npm install @grpc/proto-loader
我们再安装email处理的库
cpp
npm install nodemailer
我们将proto文件放入VarifyServer文件夹,并且新建一个proto.js用来解析proto文件
cpp
const path = require('path')
const grpc = require('@grpc/grpc-js')
const protoLoader = require('@grpc/proto-loader')
const PROTO_PATH = path.join(__dirname, 'message.proto')
const packageDefinition = protoLoader.loadSync(PROTO_PATH, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true })
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition)
const message_proto = protoDescriptor.message
module.exports = message_proto
keepCase: 如果为 true,则保留字段名的原始大小写。如果为 false,则将所有字段名转换为驼峰命名法。
longs: 控制如何表示 Protocol Buffers 中的 long 类型。如果设置为 String,则长整数会被转换为字符串,以避免 JavaScript 中的整数溢出问题。
enums: 控制如何表示 Protocol Buffers 中的枚举类型。如果设置为 String,则枚举值会被转换为字符串。
defaults: 如果为 true,则为未明确设置的字段提供默认值。
oneofs: 如果为 true,则支持 Protocol Buffers 中的 oneof 特性。
开启邮箱的smtp服务
在写代码发送邮件之前,我们先去邮箱开启smtp服务。我用的163邮箱,在邮箱设置中查找smtp服务器地址,需要开启smtp服务。这个是固定的,不需要修改。
网易163邮箱的 SMTP 服务器地址为: smtp.163.com
发送邮件,建议使用授权码(有的邮箱叫 独立密码),确保邮箱密码的安全性。授权码在邮箱设置中进行设置。如果开启了授权码,发送邮件的时候,必须使用授权码。
这里设置开启smtp服务和授权码。我这里已经是设置好的。我们新增一个授权码用于发邮件。

二、读取配置
因为我们要实现参数可配置,所以要读取配置,先在文件夹内创建一个config.json文件
user是我们得邮箱地址,pass是邮箱得授权码,只有有了授权码才能用代码发邮件。大家记得把授权码改为你们自己的,否则用我的无法发送成功。
cpp
{
"email": {
"user": "caiqiang177@163.com",
"pass": "WEtHmPPDGBUEAihx"
}
}
另外我们也要用到一些常量和全局得变量,所以我们定义一个const.js
cpp
let code_prefix = "code_";
const Errors = {
Success : 0,
RedisErr : 1,
Exception : 2,
};
module.exports = {code_prefix,Errors}
新建config.js用来读取配置
cpp
const fs = require('fs');
let config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
let email_user = config.email.user;
let email_pass = config.email.pass;
let mysql_host = config.mysql.host;
let mysql_port = config.mysql.port;
let redis_host = config.redis.host;
let redis_port = config.redis.port;
let redis_passwd = config.redis.passwd;
let code_prefix = "code_";
module.exports = {email_pass, email_user, mysql_host, mysql_port,redis_host, redis_port, redis_passwd, code_prefix}
接下来封装发邮件的模块,新建一个email.js文件
cpp
const nodemailer = require('nodemailer');
const config_module = require("./config")
/**
* 创建发送邮件的代理
*/
let transport = nodemailer.createTransport({
host: 'smtp.163.com',
port: 465,
secure: true,
auth: {
user: config_module.email_user, // 发送方邮箱地址
pass: config_module.email_pass // 邮箱授权码或者密码
}
});
接下来实现发邮件的函数
cpp
/**
* 发送邮件的函数
* @param {*} mailOptions_ 发送邮件的参数
* @returns
*/
function SendMail(mailOptions_){
return new Promise(function(resolve, reject){
transport.sendMail(mailOptions_, function(error, info){
if (error) {
console.log(error);
reject(error);
} else {
console.log('邮件已成功发送:' + info.response);
resolve(info.response)
}
});
})
}
module.exports.SendMail = SendMail
因为transport.SendMail相当于一个异步函数,调用该函数后发送的结果是通过回调函数通知的,所以我们没办法同步使用,需要用Promise封装这个调用,抛出Promise给外部,那么外部就可以通过await或者then catch的方式处理了。
我们新建server.js,用来启动grpc server
cpp
const grpc = require('@grpc/grpc-js')
const message_proto = require('./proto')
const const_module = require('./const')
const { v4: uuidv4 } = require('uuid');
const emailModule = require('./email');
//const redis_module = require('./redis')
async function GetVarifyCode(call, callback) {
console.log("email is ", call.request.email)
try{
uniqueId = uuidv4();
console.log("uniqueId is ", uniqueId)
let text_str = '您的验证码为'+ uniqueId +'请三分钟内完成注册'
//发送邮件
let mailOptions = {
from: 'caiqiang177@163.com',
to: call.request.email,
subject: '验证码',
text: text_str,
};
let send_res = await emailModule.SendMail(mailOptions);
console.log("send res is ", send_res)
callback(null, { email: call.request.email,
error:const_module.Errors.Success
});
}catch(error){
console.log("catch error is ", error)
callback(null, { email: call.request.email,
error:const_module.Errors.Exception
});
}
}
function main() {
var server =new grpc.Server();
server.addService(message_proto.VarifyService.service, { GetVarifyCode: GetVarifyCode })
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
console.log('grpc server started')
})
}
main()