前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【serverless实战】利用腾讯云·云开发实现短信验证码

【serverless实战】利用腾讯云·云开发实现短信验证码

作者头像
心谭博客
发布2020-05-06 23:34:00
3.2K0
发布2020-05-06 23:34:00
举报
文章被收录于专栏:YuanXinYuanXin

最近支持了云开发的自定义短信验证码登录功能。第一次体会到利用云开发自身能力,开箱即用的快感。所有的精力集中在业务逻辑和数据库设计上,不用花费过多的精力浪费在运维上。

环境准备

  • 前往腾讯云控制台,开通云开发
  • 打开云开发设置-匿名登录
  • 前往腾讯云控制台,开通 SMS
  • 打开 SMS,创建并审核通过短信模版

架构设计

云数据库

前往 CloudBase 控制台,创建 tcb-sms-auth 集合。集合字段信息如下:

代码语言:javascript
复制
expiration: 验证码过期时间
phone: 手机号
smsCode: 验证码

除了 expiration 字段,还需要一个多余的字段来防止验证码对同一手机,在规定时间内,重复发送。但是腾讯云 SMS 自带频控管理,所以不在数据库中添加这个字段。

云函数

支持 3 种 Action:

  • send(phone): 向手机号 phone 发送随机验证码
  • verify(phone, smsCode): 检验手机验证码是否正确
  • clear(): 定时任务清空手机验证码(前往 cloudbase 控制台-云函数-设置定时 corn)

整体架构设计如下:所有的服务都封装在 services 目录下;index.js 是入口文件,解析 C 端传入的参数,从而调用对应的 service。

image-20200504125541748
image-20200504125541748
发送随机验证码

流程如下:

step1: 查询云数据库,清空 phone 之前的验证码。保证在同一时刻,对同一个 phone,只有一个 smsCode 有效

step2: 生成随机 6 位验证码,并将其存入云数据库

代码语言:javascript
复制
/**
 * 生成验证码并存储到云数据库,发送短信
 *
 * @param {string} phone
 * @param {object} ctx
 */
async function sendSmsCode(phone, ctx) {
    const { db } = ctx;

    // 1. 移除之前的验证码
    const res = await db
        .collection(config.collection)
        .where({ phone })
        .get();

    if (res.data.length) {
        await db
            .collection(config.collection)
            .where({ phone })
            .remove();
    }

    // 2. 生成验证码
    const smsCode = randomStr(6);
    const period = 3 * 60 * 1000;
    const doc = {
        phone, // 电话号码
        smsCode, // 短信验证码
        expiration: Date.now() + period // 过期时间
    };

    await db.collection(config.collection).add(doc);

    // 3. 发送短信
    await sendSms({
        phone,
        smsCode
    });
}

step3: 调用腾讯云 SMS 服务,向 phone 发送 smsCode

代码语言:javascript
复制
/**
 * 发送短信
 *
 * @param {object} params
 */
function sendSms(params) {
    const { phone, smsCode } = params;

    const {
        TENCENTCLOUD_SECRETID,
        TENCENTCLOUD_SECRETKEY,
        TENCENTCLOUD_SESSIONTOKEN
    } = process.env;

    // 具体拼接请见:https://github.com/TencentCloud/tencentcloud-sdk-nodejs/blob/master/examples/sms/v20190711/SendSms.js
    const cred = new Credential(
        TENCENTCLOUD_SECRETID,
        TENCENTCLOUD_SECRETKEY,
        TENCENTCLOUD_SESSIONTOKEN
    );
    const client = new smsClient(cred, "ap-guangzhou");

    const req = new models.SendSmsRequest();
    req.SmsSdkAppid = config.SmsSdkAppid;
    req.Sign = config.Sign;
    req.ExtendCode = "";
    req.SenderId = "";
    req.SessionContext = "";
    req.PhoneNumberSet = [`+86${phone}`];
    req.TemplateID = config.TemplateID; // 模版类似:验证码是{1},有效期{2}
    req.TemplateParamSet = [smsCode, 3]; // 3代表3分钟

    return new Promise((resolve, reject) => {
        client.SendSms(req, (err, res) => {
            // 用于日志
            console.log(">>> sms err is", err);
            console.log(">>> sms res is", res);

            if (err) {
                err.code = "SMS_REQUEST_FAIL";
                return reject(err);
            }

            const json = JSON.parse(res.to_json_string());
            if (json.SendStatusSet[0].Code.toLowerCase() === "ok") {
                return resolve();
            }

            const error = new Error(json.SendStatusSet[0].Message);
            error.code = json.SendStatusSet[0].Code;
            return reject(error);
        });
    });
}
检验验证码有效性

利用聚合搜索,查询符合以下条件的数据库字段:

  • phone 和 smsCode 匹配 C 端传入
  • expiration 小于/等于当前时间戳
代码语言:javascript
复制
/**
 * 验证验证码是否和云数据库中一致
 *
 * @param {string} phone
 * @param {string} smsCode
 * @param {object} ctx
 * @return {Promise}
 */
async function verifySmsCode(phone, smsCode, ctx) {
    const { db, visitTime } = ctx;
    const _ = db.command;
    const res = await db
        .collection(config.collection)
        .where({
            phone,
            smsCode,
            expiration: _.gte(visitTime)
        })
        .get();

    return !!res.data.length;
}
清空过期验证码

查询 expiration 过期的所有记录,直接删除数据库记录

代码语言:javascript
复制
/**
 * 清空过期验证码
 *
 * @param {object} ctx
 */
async function clearSmsCode(ctx) {
    const { db, visitTime } = ctx;

    const _ = db.command;
    await db
        .collection(config.collection)
        .where({
            expiration: _.lt(visitTime)
        })
        .remove();
}

C 端消费

基于 tcb-js-sdk,通过匿名登录,调用短信验证码的云函数。请参考tcb-js-sdk 文档

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境准备
  • 架构设计
    • 云数据库
      • 云函数
        • 发送随机验证码
        • 检验验证码有效性
        • 清空过期验证码
      • C 端消费
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
      http://www.vxiaotou.com