登录 发送短信验证码

This commit is contained in:
Wang Kejun 2023-01-28 16:53:29 +08:00
parent 5b1f72fd53
commit a29aa55aa6
7 changed files with 277 additions and 31 deletions

View File

@ -11,6 +11,7 @@ var extraFile_1 = require("../utils/extraFile");
var Exception_1 = require("../types/Exception");
var password_1 = require("../utils/password");
var Token_1 = require("../types/Token");
var sms_1 = require("../utils/sms");
function makeDistinguishException(userId, context) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, user, password, passwordSha1, idState, wechatUser$user, email$user;
@ -1254,7 +1255,7 @@ exports.syncUserInfoWechatMp = syncUserInfoWechatMp;
function sendCaptcha(_a, context) {
var mobile = _a.mobile, env = _a.env;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var type, visitorId, now, _b, count1, count2, _c, captcha, code, code, id, _d, _e, _f;
var type, visitorId, now, duration, _b, count1, count2, _c, captcha, code, result, code, id, _d, _e, _f, result;
var _g;
return tslib_1.__generator(this, function (_h) {
switch (_h.label) {
@ -1263,6 +1264,7 @@ function sendCaptcha(_a, context) {
(0, assert_1.assert)(type === 'web');
visitorId = env.visitorId;
now = Date.now();
duration = 1;
if (!(process.env.NODE_ENV !== 'development')) return [3 /*break*/, 2];
return [4 /*yield*/, Promise.all([
context.count('captcha', {
@ -1310,20 +1312,42 @@ function sendCaptcha(_a, context) {
})];
case 3:
_c = tslib_1.__read.apply(void 0, [_h.sent(), 1]), captcha = _c[0];
if (!captcha) return [3 /*break*/, 4];
if (process.env.NODE_ENV === 'development') {
if (!captcha) return [3 /*break*/, 8];
code = captcha.code;
if (!(process.env.NODE_ENV === 'development')) return [3 /*break*/, 4];
return [2 /*return*/, "\u9A8C\u8BC1\u7801[".concat(code, "]\u5DF2\u521B\u5EFA")];
}
else if (captcha.$$createAt$$ - now < 60000) {
case 4:
if (!(captcha.$$createAt$$ - now < 60000)) return [3 /*break*/, 5];
throw new types_1.OakUserException('您的操作太迅捷啦,请稍等再点吧');
case 5: return [4 /*yield*/, (0, sms_1.sendSms)({
origin: 'tencent',
templateName: '登录',
mobile: mobile,
templateParamSet: {
code: code,
duration: duration.toString(),
},
templateParamSetFn: function (origin, templateParamSet) {
if (!templateParamSet) {
return templateParamSet;
}
else {
// todo 再次发送
if (origin === 'tencent') {
return [
templateParamSet.code,
templateParamSet.duration,
];
}
return undefined;
},
}, context)];
case 6:
result = _h.sent();
if (result === true) {
return [2 /*return*/, '验证码已发送'];
}
return [3 /*break*/, 8];
case 4:
return [2 /*return*/, '验证码发送失败'];
case 7: return [3 /*break*/, 14];
case 8:
code = void 0;
if (process.env.NODE_ENV === 'development') {
code = mobile.substring(7);
@ -1335,13 +1359,13 @@ function sendCaptcha(_a, context) {
}
}
return [4 /*yield*/, (0, uuid_1.generateNewIdAsync)()];
case 5:
case 9:
id = _h.sent();
_e = (_d = context).operate;
_f = ['captcha'];
_g = {};
return [4 /*yield*/, (0, uuid_1.generateNewIdAsync)()];
case 6: return [4 /*yield*/, _e.apply(_d, _f.concat([(_g.id = _h.sent(),
case 10: return [4 /*yield*/, _e.apply(_d, _f.concat([(_g.id = _h.sent(),
_g.action = 'create',
_g.data = {
id: id,
@ -1355,16 +1379,38 @@ function sendCaptcha(_a, context) {
_g), {
dontCollect: true,
}]))];
case 7:
case 11:
_h.sent();
if (process.env.NODE_ENV === 'development') {
if (!(process.env.NODE_ENV === 'development')) return [3 /*break*/, 12];
return [2 /*return*/, "\u9A8C\u8BC1\u7801[".concat(code, "]\u5DF2\u521B\u5EFA")];
case 12: return [4 /*yield*/, (0, sms_1.sendSms)({
origin: 'tencent',
templateName: '登录',
mobile: mobile,
templateParamSet: {
code: code,
duration: duration.toString(),
},
templateParamSetFn: function (origin, templateParamSet) {
if (!templateParamSet) {
return templateParamSet;
}
else {
return [2 /*return*/, '验证码已创建'];
if (origin === 'tencent') {
return [
templateParamSet.code,
templateParamSet.duration,
];
}
_h.label = 8;
case 8: return [2 /*return*/];
return undefined;
},
}, context)];
case 13:
result = _h.sent();
if (result === true) {
return [2 /*return*/, '验证码已发送'];
}
return [2 /*return*/, '验证码发送失败'];
case 14: return [2 /*return*/];
}
});
});

View File

@ -102,9 +102,7 @@ function Tencent(props) {
? sms.map(function (ele, idx) { return ({
key: "".concat(idx),
label: "\u77ED\u4FE1".concat(idx + 1),
children: ((0, jsx_runtime_1.jsxs)(antd_1.Form, tslib_1.__assign({ colon: false, labelAlign: "left", layout: "vertical", style: { marginTop: 10 } }, { children: [(0, jsx_runtime_1.jsx)(antd_1.Form.Item, tslib_1.__assign({ label: "secretId", name: "secretId" }, { children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(antd_1.Input, { placeholder: "\u8BF7\u8F93\u5165secretId", type: "text", value: ele.secretId, onChange: function (e) {
return setValue("".concat(idx, ".secretId"), e.target.value);
} }) }) })), (0, jsx_runtime_1.jsx)(antd_1.Form.Item, tslib_1.__assign({ label: "smsSdkAppId", name: "smsSdkAppId" }, { children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(antd_1.Input, { placeholder: "\u8BF7\u8F93\u5165smsSdkAppId", type: "text", value: ele.smsSdkAppId, onChange: function (e) {
children: ((0, jsx_runtime_1.jsxs)(antd_1.Form, tslib_1.__assign({ colon: false, labelAlign: "left", layout: "vertical", style: { marginTop: 10 } }, { children: [(0, jsx_runtime_1.jsx)(antd_1.Form.Item, tslib_1.__assign({ label: "smsSdkAppId", name: "smsSdkAppId" }, { children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(antd_1.Input, { placeholder: "\u8BF7\u8F93\u5165smsSdkAppId", type: "text", value: ele.smsSdkAppId, onChange: function (e) {
return setValue("".concat(idx, ".smsSdkAppId"), e.target.value);
} }) }) })), (0, jsx_runtime_1.jsx)(antd_1.Form.Item, tslib_1.__assign({ label: "defaultSignName", name: "defaultSignName" }, { children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(antd_1.Input, { placeholder: "\u8BF7\u8F93\u5165defaultSignName", type: "text", value: ele.defaultSignName, onChange: function (e) {
return setValue("".concat(idx, ".defaultSignName"), e.target.value);

9
lib/utils/sms.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
import { EntityDict } from '../general-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
export declare function sendSms<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(options: {
origin: 'ali' | 'tencent';
templateName: string;
mobile: string;
templateParamSet?: Record<string, string>;
templateParamSetFn?: (origin: 'ali' | 'tencent', templateParamSet?: Record<string, string>) => string[] | Record<string, string> | undefined;
}, context: Cxt): Promise<boolean>;

54
lib/utils/sms.js Normal file
View File

@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sendSms = void 0;
var tslib_1 = require("tslib");
var oak_external_sdk_1 = require("oak-external-sdk");
var assert_1 = require("oak-domain/lib/utils/assert");
function sendSms(options, context) {
var _a, _b, _c, _d, _e;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var origin, templateName, mobile, templateParamSet, templateParamSetFn, application, system, _f, platform, systemConfig, platformConfig, accountConfigs, smsConfigs, templateParamSet2, accountConfig, smsConfig, template, SmsSdkInstance, data, sendStatus;
return tslib_1.__generator(this, function (_g) {
switch (_g.label) {
case 0:
origin = options.origin, templateName = options.templateName, mobile = options.mobile, templateParamSet = options.templateParamSet, templateParamSetFn = options.templateParamSetFn;
application = context.getApplication();
system = application.system;
_f = system, platform = _f.platform, systemConfig = _f.config;
platformConfig = platform.config;
accountConfigs = ((_a = systemConfig === null || systemConfig === void 0 ? void 0 : systemConfig.Account) === null || _a === void 0 ? void 0 : _a[origin]) || ((_b = platformConfig === null || platformConfig === void 0 ? void 0 : platformConfig.Account) === null || _b === void 0 ? void 0 : _b[origin]);
smsConfigs = ((_c = systemConfig === null || systemConfig === void 0 ? void 0 : systemConfig.Sms) === null || _c === void 0 ? void 0 : _c[origin]) || ((_d = platformConfig === null || platformConfig === void 0 ? void 0 : platformConfig.Sms) === null || _d === void 0 ? void 0 : _d[origin]);
if (!accountConfigs ||
accountConfigs.length === 0 ||
!smsConfigs ||
smsConfigs.length === 0) {
(0, assert_1.assert)(false, "".concat(origin, "\u77ED\u4FE1\u672A\u914D\u7F6E"));
}
templateParamSet2 = templateParamSetFn
? templateParamSetFn(origin, templateParamSet)
: templateParamSet;
if (!(origin === 'tencent')) return [3 /*break*/, 2];
accountConfig = accountConfigs[0];
smsConfig = smsConfigs[0];
template = (_e = smsConfig.templates) === null || _e === void 0 ? void 0 : _e[templateName];
SmsSdkInstance = oak_external_sdk_1.SmsSdk.getInstance(origin, accountConfig.secretId, accountConfig.secretKey, accountConfig.region, accountConfig.endpoint);
return [4 /*yield*/, SmsSdkInstance.sendSms({
PhoneNumberSet: [mobile],
SmsSdkAppId: smsConfig.smsSdkAppId,
SignName: template.signName || smsConfig.defaultSignName,
TemplateId: template.code,
TemplateParamSet: templateParamSet2,
})];
case 1:
data = _g.sent();
sendStatus = data.SendStatusSet[0];
if (sendStatus.Code === 'Ok') {
return [2 /*return*/, true];
}
return [2 /*return*/, false];
case 2: throw new Error('未实现');
}
});
});
}
exports.sendSms = sendSms;

View File

@ -14,6 +14,7 @@ import { OakChangeLoginWayException, OakDistinguishUserException, OakUserDisable
import { encryptPasswordSha1 } from '../utils/password';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
import { tokenProjection } from '../types/Token';
import { sendSms } from '../utils/sms';
async function makeDistinguishException<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(userId: string, context: Cxt) {
const [user] = await context.select('user', {
@ -1023,6 +1024,7 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends BackendRunt
assert(type === 'web');
let { visitorId } = env;
const now = Date.now();
const duration = 1; // 多少分钟内有效
if (process.env.NODE_ENV !== 'development') {
const [count1, count2] = await Promise.all(
[
@ -1069,8 +1071,8 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends BackendRunt
dontCollect: true,
});
if (captcha) {
const code = captcha.code!;
if (process.env.NODE_ENV === 'development') {
const { code } = captcha;
return `验证码[${code}]已创建`;
}
else if (captcha.$$createAt$$! as number - now < 60000) {
@ -1078,8 +1080,35 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends BackendRunt
}
else {
// todo 再次发送
const result = await sendSms<ED, Cxt>(
{
origin: 'tencent',
templateName: '登录',
mobile,
templateParamSet: {
code,
duration: duration.toString(),
},
templateParamSetFn: (origin, templateParamSet) => {
if (!templateParamSet) {
return templateParamSet;
}
if (origin === 'tencent') {
return [
templateParamSet.code,
templateParamSet.duration,
];
}
return undefined;
},
},
context
);
if (result === true) {
return '验证码已发送';
}
return '验证码发送失败';
}
}
else {
let code: string;
@ -1114,7 +1143,35 @@ export async function sendCaptcha<ED extends EntityDict, Cxt extends BackendRunt
return `验证码[${code}]已创建`;
}
else {
return '验证码已创建';
//发送短信
const result = await sendSms<ED, Cxt>(
{
origin: 'tencent',
templateName: '登录',
mobile,
templateParamSet: {
code,
duration: duration.toString(),
},
templateParamSetFn: (origin, templateParamSet) => {
if (!templateParamSet) {
return templateParamSet;
}
if (origin === 'tencent') {
return [
templateParamSet.code,
templateParamSet.duration,
];
}
return undefined;
},
},
context
);
if (result === true) {
return '验证码已发送';
}
return '验证码发送失败';
}
}
}

View File

@ -305,7 +305,7 @@ function Tencent(props: {
layout="vertical"
style={{ marginTop: 10 }}
>
<Form.Item
{/* <Form.Item
label="secretId"
name="secretId"
>
@ -322,7 +322,7 @@ function Tencent(props: {
}
/>
</>
</Form.Item>
</Form.Item> */}
<Form.Item
label="smsSdkAppId"
name="smsSdkAppId"

82
src/utils/sms.ts Normal file
View File

@ -0,0 +1,82 @@
import { SmsSdk, TencentSmsInstance } from 'oak-external-sdk';
import { assert } from 'oak-domain/lib/utils/assert';
import { EntityDict } from '../general-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
import {
TencentSmsConfig,
TencentCloudConfig,
AliCloudConfig,
AliSmsConfig,
} from '../types/Config';
export async function sendSms<
ED extends EntityDict,
Cxt extends BackendRuntimeContext<ED>
>(
options: {
origin: 'ali' | 'tencent';
templateName: string;
mobile: string;
templateParamSet?: Record<string, string>;
templateParamSetFn?: (
origin: 'ali' | 'tencent',
templateParamSet?: Record<string, string>
) => string[] | Record<string, string> | undefined;
},
context: Cxt
) {
const {
origin,
templateName,
mobile,
templateParamSet,
templateParamSetFn,
} = options;
const application = context.getApplication();
const { system } = application!;
const { platform, config: systemConfig } = system!;
const { config: platformConfig } = platform;
const accountConfigs =
systemConfig?.Account?.[origin] || platformConfig?.Account?.[origin];
const smsConfigs =
systemConfig?.Sms?.[origin] || platformConfig?.Sms?.[origin];
if (
!accountConfigs ||
accountConfigs.length === 0 ||
!smsConfigs ||
smsConfigs.length === 0
) {
assert(false, `${origin}短信未配置`);
}
const templateParamSet2 = templateParamSetFn
? templateParamSetFn(origin, templateParamSet)
: templateParamSet;
if (origin === 'tencent') {
const accountConfig = accountConfigs[0] as TencentCloudConfig;
const smsConfig = smsConfigs[0] as TencentSmsConfig;
const template = smsConfig.templates?.[templateName];
const SmsSdkInstance = SmsSdk.getInstance(
origin,
accountConfig.secretId,
accountConfig.secretKey,
accountConfig.region,
accountConfig.endpoint
) as TencentSmsInstance;
const data = await SmsSdkInstance.sendSms({
PhoneNumberSet: [mobile],
SmsSdkAppId: smsConfig.smsSdkAppId,
SignName: template.signName || smsConfig.defaultSignName,
TemplateId: template.code,
TemplateParamSet: templateParamSet2 as string[],
});
const sendStatus = data.SendStatusSet[0];
if (sendStatus.Code === 'Ok') {
return true;
}
return false;
} else {
throw new Error('未实现');
}
}