chore: 后端首次基线提交
运行必须源码:app/(controller/model/service/middleware/lib/utils/validate/router)、config/、database/(migrations/seeders/sql)、启动脚本、app/public/templates 模板。 已忽略运行非必须:node_modules/、logs/、run/、app/public 运行时上传数据、.env*、构建/缓存产物。
This commit is contained in:
78
app/service/sms.js
Normal file
78
app/service/sms.js
Normal file
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
const Service = require('egg').Service;
|
||||
|
||||
/**
|
||||
* 短信网关服务(阿里云 Dysmsapi)
|
||||
*
|
||||
* 仅负责把"服务端已生成的验证码"下发给手机号,不参与验证码的存证与校验
|
||||
* (校验仍由 ctx.session 在 auth 控制器中完成,契约见 verify_sms_and_import_lock 测试)。
|
||||
*
|
||||
* 依赖 SDK(生产环境需 npm install):
|
||||
* @alicloud/openapi-client
|
||||
* @alicloud/dysmsapi20170525
|
||||
* @alicloud/tea-util
|
||||
*/
|
||||
class SmsService extends Service {
|
||||
/**
|
||||
* 发送短信验证码
|
||||
* @param {string} phone - 接收短信的手机号
|
||||
* @param {string} code - 6 位验证码(由调用方生成并存入 session)
|
||||
* @returns {Promise<{ok:boolean, message:string}>}
|
||||
*/
|
||||
async sendVerifyCode(phone, code) {
|
||||
const { ctx, app } = this;
|
||||
const cfg = app.config.sms && app.config.sms.aliyun;
|
||||
if (!cfg || !cfg.accessKeyId || !cfg.accessKeySecret) {
|
||||
ctx.logger.error('[短信网关] 未配置阿里云密钥,无法发送');
|
||||
return { ok: false, message: '短信网关未配置' };
|
||||
}
|
||||
|
||||
let OpenApi;
|
||||
let Dysmsapi;
|
||||
let Util;
|
||||
try {
|
||||
OpenApi = require('@alicloud/openapi-client');
|
||||
Dysmsapi = require('@alicloud/dysmsapi20170525');
|
||||
Util = require('@alicloud/tea-util');
|
||||
} catch (e) {
|
||||
ctx.logger.error('[短信网关] 未安装阿里云 SDK:' + e.message);
|
||||
return { ok: false, message: '短信网关 SDK 未安装' };
|
||||
}
|
||||
|
||||
try {
|
||||
const config = new OpenApi.Config({
|
||||
accessKeyId: cfg.accessKeyId,
|
||||
accessKeySecret: cfg.accessKeySecret,
|
||||
endpoint: cfg.endpoint,
|
||||
});
|
||||
const client = new Dysmsapi.default(config);
|
||||
|
||||
const request = new Dysmsapi.SendSmsRequest({
|
||||
phoneNumbers: String(phone),
|
||||
signName: cfg.signName,
|
||||
templateCode: cfg.templateCode,
|
||||
templateParam: JSON.stringify({ code: String(code) }),
|
||||
});
|
||||
|
||||
const runtime = new Util.RuntimeOptions({});
|
||||
runtime.readTimeout = 5000;
|
||||
runtime.connectTimeout = 5000;
|
||||
|
||||
const response = await client.sendSmsWithOptions(request, runtime);
|
||||
const body = response && response.body;
|
||||
if (body && body.code === 'OK') {
|
||||
ctx.logger.info(`[短信网关] 验证码已下发至 ${phone}`);
|
||||
return { ok: true, message: '验证码发送成功' };
|
||||
}
|
||||
const reason = (body && (body.message || body.code)) || '未知错误';
|
||||
ctx.logger.error(`[短信网关] 下发失败:${reason}`);
|
||||
return { ok: false, message: reason };
|
||||
} catch (err) {
|
||||
ctx.logger.error('[短信网关] 调用异常:' + (err && err.message));
|
||||
return { ok: false, message: (err && err.message) || '短信网关调用异常' };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SmsService;
|
||||
Reference in New Issue
Block a user