Nodejs中如何调⽤腾讯云的短信验证码接⼝并对接⼝进⾏安全限制
简介
在我们的实际开发当中我们会遇到使⽤腾讯云短信验证码或者阿⾥云短信验证码接⼝等等,这样就需要我们后端去处理这个请求和相关的逻辑判断,这个肯定是不能前端进⾏验证的,不然就等于直接告诉⼤家⾃⼰的腾讯云配置的secretId和secretKey。是⼗分的不安全。
开始
既然我们已经知道了具体要实现的功能,那么我们接下就是去实现这个功能。在实现的开发中也是要这样的,先分析功能做出实现此功能的架构,我们再去写代码,这样机会提⾼很多⼯作效率⽽且项⽬上线后也不会出现bug。
针对此功能我的实现逻辑设计是这样的
1. 我们先对⼿机号进⾏验证判断是否是有效的⼿机号
2. 使⽤math函数⽣成6位随机整数
3. 请求腾讯云的短信服务接⼝给⽤户
4. 将发送成功的短信存到redis中并在字段中设置number⽤于统计此⼿机号验证码的次数
5. 然后在将发送成功的验证码存到session中,便于后⾯的登录判断使⽤
⼤概的实现逻辑我们清楚了,接下来就是敲代码环境
代码部分
对⼿机号的格式验证我们使⽤正则来进⾏匹配
const phone = req.body.phone //POST请求上来的⼿机号
phone.match(/^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/g)
如果⼿机号格式正确会返回⼀个数组,否则就是null或者空数组
接下来就是⽣成6位的随机整数
const code = und(Math.random()*(899999)+100000)
console.log(code)
调⽤腾讯云的短信接⼝,我们就可以参考腾讯云官⽅的⽰例session如何设置和读取
redis和session没啥好说的直接导⼊包,然后封装⼀下就可以了,下⼀篇⽂章我会放出来redis的配置和session的配置,这⾥就不多说废话了。
基本上需要的部分都搞定了接下来就是完整的实现代码
对⼿机号这种数据我们⽤过进⾏加密传参,所以我使⽤了base64加密
/*
* @Author: zhizhuo
* @Date: 2022-03-25 10:08:57
* @Last Modified by: zhizhuo
* @Last Modified time: 2022-03-25 14:24:30
*/
const models =require('../../models')
const tencentcloud =require("tencentcloud-sdk-nodejs")
const{ setString, getString }=require('../../redis')
const Base64 =require('js-base64')
const moment =require('moment')
// 导⼊对应产品模块的client models。
const smsClient = tencentcloud.sms.v20210111.Client
//腾讯云短信配置⽂件,这些在腾讯云控制台都能看见
const config ={
secretId:'',
secretKey:'',
SmsSdkAppId:"",
SignName:"",
TemplateId:"",
Time:5,
timenow:moment().format('YYYYMMDD')+'00',
timeend:moment().format('YYYYMMDD')+'23',
time_now:moment().format("YYYY-MM-DD HH:mm:ss"),
time_end:moment().format("YYYY-MM-DD")+' 23:59:59'
}
class Code {
//获取短信验证码接⼝/
async getcode(req, res){
try{
const phone = Base64.decode(req.body.phone)
const code = und(Math.random()*(899999)+100000)
const time_key =moment(moment().format("YYYY-MM-DD")+' 23:59:59').diff(moment(moment().format("YYYY-MM-DD HH:mm:ss")),'seconds') if(!phone || phone.length !=11||!phone.match(/^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/g)|| phone.match(/^(13[0-9]|1 4[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/g)[0].length !=11){
var data ={
code:500,
msg:'请输⼊⼿机号'
}
res.json(data)
return
}
const client =new smsClient({
credential:{
secretId: config.secretId,
secretKey: config.secretKey,
},
/* 必填:地域信息,可以直接填写字符串ap-guangzhou,⽀持的地域列表参考 t/document/api/382/52071#.E5.9C.B0.E5.9 F.9F.E5.88.97.E8.A1.A8 */
region:"ap-guangzhou",
/* ⾮必填:
* 客户端配置对象,可以指定超时时间等配置 */
profile:{
/* SDK默认⽤TC3-HMAC-SHA256进⾏签名,⾮必要请不要修改这个字段 */
signMethod:"HmacSHA256",
httpProfile:{
/* SDK默认使⽤POST⽅法。
* 如果你⼀定要使⽤GET⽅法,可以在这⾥设置。GET⽅法⽆法处理⼀些较⼤的请求 */
reqMethod:"POST",
/* SDK有默认的超时时间,⾮必要请不要进⾏调整
* 如有需要请在代码中查阅以获取最新的默认值 */
reqTimeout:30,
/**
* 指定接⼊地域域名,默认就近地域接⼊域名为 tcloudapi ,也⽀持指定地域域名访问,例如⼴州地域的域名为 sms.tcloudapi
*/
endpoint:"tcloudapi"
},
},
})
/* 请求参数,根据调⽤的接⼝和实际情况,可以进⼀步设置请求参数
* 属性可能是基本类型,也可能引⽤了另⼀个数据结构
* 推荐使⽤IDE进⾏开发,可以⽅便的跳转查阅各个接⼝和数据结构的⽂档说明 */
// const params2 = {
/
/    // 短信应⽤ID: 短信SdkAppId在 [短信控制台] 添加应⽤后⽣成的实际SdkAppId,⽰例如1400006666
//    SmsSdkAppId: config.SmsSdkAppId,
//    // 拉取最⼤条数,最多100条
//    Limit: 100,
// }
// // 通过client对象调⽤想要访问的接⼝,需要传⼊请求对象以及响应回调函数
// client.PullSmsSendStatus(params2, function (err, response) {
// client.PullSmsSendStatus(params2, function (err, response) {
//    // 请求异常返回,打印异常信息
//    if (err) {
//        console.log(err)
//        return
//    }
//    // 请求正常返回,打印response对象
//    console.log(response)
//    res.json(response)
// })
/* 请求参数,根据调⽤的接⼝和实际情况,可以进⼀步设置请求参数
* 属性可能是基本类型,也可能引⽤了另⼀个数据结构
* 推荐使⽤IDE进⾏开发,可以⽅便的跳转查阅各个接⼝和数据结构的⽂档说明 */
// const params1 = {
//    // 短信应⽤ID: 短信SdkAppId在 [短信控制台] 添加应⽤后⽣成的实际SdkAppId,⽰例如1400006666
//    SmsSdkAppId: config.SmsSdkAppId,
//    // 拉取最⼤条数,最多100条
//    Limit: 10,
//    // 偏移量注:⽬前固定设置为0
//    Offset: 0,
//    // 开始时间,yyyymmddhh 需要拉取的起始时间,精确到⼩时
//    BeginTime: config.timenow,
//    // 结束时间,yyyymmddhh 需要拉取的截⽌时间,精确到⼩时
//    // 注:EndTime 必须⼤于 BeginTime
//    EndTime: config.timeend,
// }
/
/ 通过client对象调⽤想要访问的接⼝,需要传⼊请求对象以及响应回调函数
// client.SendStatusStatistics(params1, function (err, response) {
//    // 请求异常返回,打印异常信息
//    if (err) {
//        console.log(err)
//        return
//    }
//    // 请求正常返回,打印response对象
//    console.log(response)
// })
const params ={
/
* 短信应⽤ID: 短信SmsSdkAppId在 [短信控制台] 添加应⽤后⽣成的实际SmsSdkAppId,⽰例如1400006666 */
// 应⽤ ID 可前往 [短信控制台](t/smsv2/app-manage) 查看
SmsSdkAppId: config.SmsSdkAppId,
/* 短信签名内容: 使⽤ UTF-8 编码,必须填写已审核通过的签名 */
// 签名信息可前往 [国内短信](t/smsv2/csms-sign) 或 [国际/港澳台短信](t/smsv2/i sms-sign) 的签名管理查看
SignName: config.SignName,
/* 模板 ID: 必须填写已审核通过的模板 ID */
// 模板 ID 可前往 [国内短信](t/smsv2/csms-template) 或 [国际/港澳台短信](t/sms v2/isms-template) 的正⽂模板管理查看
TemplateId: config.TemplateId,
/
* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持⼀致,若⽆模板参数,则设置为空 */
TemplateParamSet:[code, config.Time],
/* 下发⼿机号码,采⽤ e.164 标准,+[国家或地区码][⼿机号]
* ⽰例如:+86137********,其中前⾯有⼀个+号,86为国家码,137********为⼿机号,最多不要超过200个⼿机号*/
PhoneNumberSet:['+86'+ phone],
/* ⽤户的 session 内容(⽆需要可忽略): 可以携带⽤户侧 ID 等上下⽂信息,server 会原样返回 */
SessionContext:"",
/* 短信码号扩展号(⽆需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信⼩助⼿] */
ExtendCode:"",
/* 国际/港澳台短信 senderid(⽆需要可忽略): 国内短信填空,默认未开通,如需开通请联系 [腾讯云
短信⼩助⼿] */
SenderId:"",
}
//在redis中读取⼀下这个⼿机号是否发送过短信
var getresult =JSON.parse(await getString(phone))
const time_last =moment(moment().format("YYYY-MM-DD HH:mm:ss")).diff(ate_time),'minutes')
const again =5-moment(moment().format("YYYY-MM-DD HH:mm:ss")).diff(ate_time),'minutes')
if(time_last <5){
if(time_last <5){
var data ={
code:500,
msg:'请过'+ again +'分钟后再尝试'
}
res.json(data)
return
}
if(!getresult || getresult.number >5){
send_code(phone, code, getresult)
}else{
var data ={
code:500,
msg:'此⼿机号今⽇获取验证码次数已达上线,请24⼩时后重试'
}
res.json(data)
}
// 通过client对象调⽤想要访问的接⼝,需要传⼊请求对象以及响应回调函数
function send_code(phone, code, getresult){
client.SendSms(params,async function(err, response){
// 请求异常返回,打印异常信息
// if (err) {
//    console.log(err)
//    return
/
/ }
// 请求正常返回,打印response对象
if(response.SendStatusSet[0].Code =='Ok'){
let number =0
if(getresult){
number = getresult.number +1
}else{
number =1
}
var code_data ={
code: code,
number: number,
create_time:moment().format("YYYY-MM-DD HH:mm:ss"),
}
//在redis中统计此⽤户的请求次数
var result =await setString(phone,JSON.stringify(code_data), time_key)
//在session中设置验证码code
if(de){
delete de//销毁session让⽤户重新获取新的session
de = code // session 存储验证码数值
}else{
de = code // session 存储验证码数值
}
var data ={
code:200,
msg:'发送成功'
}
res.json(data)
}else{
var data ={
code:500,
msg:'发送失败,请稍后重试'
}
res.json(data)
}
})
}
}catch(error){
var data ={
code:500,
msg:'异常请求'
}
}
res.json(data)
}
}
}
我使⽤redis统计了该⼿机获取验证码的次数,⽤于判断是否正常的⽤于避免有⼈⽽已使⽤接⼝,导致短信资源被浪费
登录部分的验证:
/*
* @Author: zhizhuo
* @Date: 2022-02-08 17:52:00
* @Last Modified by: zhizhuo
* @Last Modified time: 2022-03-25 14:29:19
*/
const models =require('../../models')
const djangoHash =require('django-hash')
const createToken =require('../../token/token')
const aes =require('../../AES/index')
const moment =require('moment')
const Base64 =require('js-base64')
class User {
async login(req, res){
var username = Base64.decode(req.body.username)
var password = Base64.decode(req.body.password)
var code = Base64.decode(de)
if(username && password){
if(username.length >11|| username.length <11||!username.match(/^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/g)|| user name.match(/^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/g)[0].length !=11){
var data ={
code:500,
msg:'账号输⼊有误,请重新输⼊'
}
delete de//销毁session让⽤户重新获取新的session
req.session.destroy()//销毁session
res.json(data)
}else if(password.length >18){
var data ={
code:500,
msg:'密码输⼊长度过长,请重新输⼊'
}
delete de//销毁session让⽤户重新获取新的session
req.session.destroy()//销毁session
res.json(data)
}else if(password.length <6){
var data ={
code:500,
msg:'密码输⼊长度过短,请重新输⼊'
}
delete de//销毁session让⽤户重新获取新的session
req.session.destroy()//销毁session
res.json(data)
}else if(!de){
var data ={
code:500,
msg:'验证码已经过期请重新输⼊'
}
delete de//销毁session让⽤户重新获取新的session
req.session.destroy()//销毁session
res.json(data)
}else if(code =!de){
var data ={

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。