2025-09-18

省市区接口、sms接口
This commit is contained in:
2025-09-19 10:00:12 +08:00
parent 9c8724f0cb
commit 3710f23dc3
11 changed files with 784 additions and 146 deletions

68
.env Normal file
View File

@@ -0,0 +1,68 @@
# 数据库配置
DB_HOST=114.55.111.44
DB_USER=maov2
DB_PASSWORD=5fYhw8z6T62b7heS
DB_NAME=maov2
# JWT密钥
JWT_SECRET=your_jwt_secret_key
# 阿里云短信服务配置
# 请在阿里云控制台获取以下配置信息:
# 1. AccessKey ID 和 AccessKey Secret在阿里云控制台 -> AccessKey管理中创建
# 2. 短信签名:在阿里云短信服务控制台中申请并审核通过的签名
# 3. 短信模板CODE在阿里云短信服务控制台中申请并审核通过的模板CODE
ALIYUN_ACCESS_KEY_ID=LTAI5tBHymRUu1vvo5tgYpaa
ALIYUN_ACCESS_KEY_SECRET=lNsDZvpUVX2b3pfBQCBawOEyr3dNB9
ALIYUN_SMS_SIGN_NAME=宁波炬融歆创科技
ALIYUN_SMS_TEMPLATE_CODE=SMS_324470054
# 环境配置
NODE_ENV=development
PORT=3000
# 前端地址配置
FRONTEND_URL=https://www.zrbjr.com/frontend
# FRONTEND_URL=http://114.55.111.44:3001/frontend
# MinIO 对象存储配置
# MinIO服务器地址不包含协议
MINIO_ENDPOINT=114.55.111.44
# MinIO服务器端口
MINIO_PORT=9000
# 是否使用SSLtrue/false
MINIO_USE_SSL=false
# MinIO访问密钥
MINIO_ACCESS_KEY=minio
# MinIO秘密密钥
MINIO_SECRET_KEY=CNy6fMCfyfeaEjbE
# MinIO公开访问地址用于生成文件URL
MINIO_PUBLIC_URL=https://minio.zrbjr.com
# MinIO存储桶配置
MINIO_BUCKET_UPLOADS=jurongquan
MINIO_BUCKET_AVATARS=jurongquan
MINIO_BUCKET_PRODUCTS=jurongquan
MINIO_BUCKET_DOCUMENTS=jurongquan
#支付配置
WECHAT_APP_ID=wx3a702dbe13fd2217
WECHAT_MCH_ID=1726377336
WECHAT_API_KEY=NINGBOJURONGkejiyouxiangongsi202
WECHAT_API_V3_KEY=NINGBOJURONGkejiyouxiangongsi202
WECHAT_CERT_PATH=./cert/apiclient_cert.pem
WECHAT_KEY_PATH=./cert/apiclient_key.pem
WECHAT_NOTIFY_URL=https://www.zrbjr.com/api/wechat-pay/notify
# 支付宝配置
# 请在支付宝开放平台获取以下配置信息:
# 1. 应用ID在支付宝开放平台创建应用后获得
# 2. 应用私钥和支付宝公钥现在从文件读取
ALIPAY_APP_ID=2021005188682022
ALIPAY_NOTIFY_URL=https://www.zrbjr.com/api/payment/alipay/notify
ALIPAY_RETURN_URL=https://www.zrbjr.com/payment
ALIPAY_QUIT_URL=https://www.zrbjr.com/payment/
#ALIPAY_APP_ID=9021000151699946
#ALIPAY_NOTIFY_URL=https://test.zrbjr.com/api/payment/alipay/notify
#ALIPAY_RETURN_URL=http://192.168.1.124:5173/frontend/payment
#ALIPAY_QUIT_URL=http://192.168.1.124:5173/frontend/payment

1
.gitignore vendored
View File

@@ -1 +1,2 @@
/node_modules/
/.idea/

10
app.js
View File

@@ -6,11 +6,12 @@ const {specs, swaggerUi} = require('./config/swagger'); // 引入 swagger 配
const cors = require('cors');
const bodyParser = require('body-parser');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// region api导入
var commonRouter = require('./routes/common');
var captchaRouter = require('./routes/captcha');
var authRouter = require('./routes/auth');
var smsRouter = require('./routes/sms');
// endregion
var app = express();
@@ -42,10 +43,11 @@ app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/users', usersRouter);
// region api配置
app.use('/api/common', commonRouter)
app.use('/api/captcha', captchaRouter)
app.use('/api/auth', authRouter)
app.use('/api/sms', smsRouter)
// endregion
module.exports = app;

470
package-lock.json generated
View File

@@ -8,8 +8,10 @@
"name": "middle-office-system",
"version": "0.0.0",
"dependencies": {
"@alicloud/dysmsapi20170525": "^4.1.1",
"@alicloud/openapi-client": "^0.4.15",
"bcryptjs": "^2.4.3",
"body-parser": "^2.2.0",
"body-parser": "^1.20.2",
"cookie-parser": "~1.4.4",
"cors": "^2.8.5",
"debug": "~2.6.9",
@@ -21,6 +23,185 @@
"swagger-ui-express": "^5.0.1"
}
},
"node_modules/@alicloud/credentials": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@alicloud/credentials/-/credentials-2.4.4.tgz",
"integrity": "sha512-/eRAGSKcniLIFQ1UCpDhB/IrHUZisQ1sc65ws/c2avxUMpXwH1rWAohb76SVAUJhiF4mwvLzLJM1Mn1XL4Xe/Q==",
"dependencies": {
"@alicloud/tea-typescript": "^1.8.0",
"httpx": "^2.3.3",
"ini": "^1.3.5",
"kitx": "^2.0.0"
}
},
"node_modules/@alicloud/darabonba-array": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@alicloud/darabonba-array/-/darabonba-array-0.1.2.tgz",
"integrity": "sha512-ZPuQ+bJyjrd8XVVm55kl+ypk7OQoi1ZH/DiToaAEQaGvgEjrTcvQkg71//vUX/6cvbLIF5piQDvhrLb+lUEIPQ==",
"dependencies": {
"@alicloud/tea-typescript": "^1.7.1"
}
},
"node_modules/@alicloud/darabonba-encode-util": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@alicloud/darabonba-encode-util/-/darabonba-encode-util-0.0.2.tgz",
"integrity": "sha512-mlsNctkeqmR0RtgE1Rngyeadi5snLOAHBCWEtYf68d7tyKskosXDTNeZ6VCD/UfrUu4N51ItO8zlpfXiOgeg3A==",
"dependencies": {
"moment": "^2.29.1"
}
},
"node_modules/@alicloud/darabonba-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@alicloud/darabonba-map/-/darabonba-map-0.0.1.tgz",
"integrity": "sha512-2ep+G3YDvuI+dRYVlmER1LVUQDhf9kEItmVB/bbEu1pgKzelcocCwAc79XZQjTcQGFgjDycf3vH87WLDGLFMlw==",
"dependencies": {
"@alicloud/tea-typescript": "^1.7.1"
}
},
"node_modules/@alicloud/darabonba-signature-util": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/@alicloud/darabonba-signature-util/-/darabonba-signature-util-0.0.4.tgz",
"integrity": "sha512-I1TtwtAnzLamgqnAaOkN0IGjwkiti//0a7/auyVThdqiC/3kyafSAn6znysWOmzub4mrzac2WiqblZKFcN5NWg==",
"dependencies": {
"@alicloud/darabonba-encode-util": "^0.0.1"
}
},
"node_modules/@alicloud/darabonba-signature-util/node_modules/@alicloud/darabonba-encode-util": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@alicloud/darabonba-encode-util/-/darabonba-encode-util-0.0.1.tgz",
"integrity": "sha512-Sl5vCRVAYMqwmvXpJLM9hYoCHOMsQlGxaWSGhGWulpKk/NaUBArtoO1B0yHruJf1C5uHhEJIaylYcM48icFHgw==",
"dependencies": {
"@alicloud/tea-typescript": "^1.7.1",
"moment": "^2.29.1"
}
},
"node_modules/@alicloud/darabonba-string": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@alicloud/darabonba-string/-/darabonba-string-1.0.3.tgz",
"integrity": "sha512-NyWwrU8cAIesWk3uHL1Q7pTDTqLkCI/0PmJXC4/4A0MFNAZ9Ouq0iFBsRqvfyUujSSM+WhYLuTfakQXiVLkTMA==",
"dependencies": {
"@alicloud/tea-typescript": "^1.5.1"
}
},
"node_modules/@alicloud/dysmsapi20170525": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@alicloud/dysmsapi20170525/-/dysmsapi20170525-4.2.0.tgz",
"integrity": "sha512-XXwOWUKEVFcfbqmJXw616ekHFp3jmaUC0OadYZs77TdMr0D13W41MuiFevKRNL09W5N0e+0GKdDErwvPuVGCpw==",
"dependencies": {
"@alicloud/openapi-core": "^1.0.0",
"@darabonba/typescript": "^1.0.0"
}
},
"node_modules/@alicloud/endpoint-util": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@alicloud/endpoint-util/-/endpoint-util-0.0.1.tgz",
"integrity": "sha512-+pH7/KEXup84cHzIL6UJAaPqETvln4yXlD9JzlrqioyCSaWxbug5FUobsiI6fuUOpw5WwoB3fWAtGbFnJ1K3Yg==",
"dependencies": {
"@alicloud/tea-typescript": "^1.5.1",
"kitx": "^2.0.0"
}
},
"node_modules/@alicloud/gateway-pop": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@alicloud/gateway-pop/-/gateway-pop-0.0.6.tgz",
"integrity": "sha512-KF4I+JvfYuLKc3fWeWYIZ7lOVJ9jRW0sQXdXidZn1DKZ978ncfGf7i0LBfONGk4OxvNb/HD3/0yYhkgZgPbKtA==",
"dependencies": {
"@alicloud/credentials": "^2",
"@alicloud/darabonba-array": "^0.1.0",
"@alicloud/darabonba-encode-util": "^0.0.2",
"@alicloud/darabonba-map": "^0.0.1",
"@alicloud/darabonba-signature-util": "^0.0.4",
"@alicloud/darabonba-string": "^1.0.2",
"@alicloud/endpoint-util": "^0.0.1",
"@alicloud/gateway-spi": "^0.0.8",
"@alicloud/openapi-util": "^0.3.2",
"@alicloud/tea-typescript": "^1.7.1",
"@alicloud/tea-util": "^1.4.8"
}
},
"node_modules/@alicloud/gateway-spi": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/@alicloud/gateway-spi/-/gateway-spi-0.0.8.tgz",
"integrity": "sha512-KM7fu5asjxZPmrz9sJGHJeSU+cNQNOxW+SFmgmAIrITui5hXL2LB+KNRuzWmlwPjnuA2X3/keq9h6++S9jcV5g==",
"dependencies": {
"@alicloud/credentials": "^2",
"@alicloud/tea-typescript": "^1.7.1"
}
},
"node_modules/@alicloud/openapi-client": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/@alicloud/openapi-client/-/openapi-client-0.4.15.tgz",
"integrity": "sha512-4VE0/k5ZdQbAhOSTqniVhuX1k5DUeUMZv74degn3wIWjLY6Bq+hxjaGsaHYlLZ2gA5wUrs8NcI5TE+lIQS3iiA==",
"dependencies": {
"@alicloud/credentials": "^2.4.2",
"@alicloud/gateway-spi": "^0.0.8",
"@alicloud/openapi-util": "^0.3.2",
"@alicloud/tea-typescript": "^1.7.1",
"@alicloud/tea-util": "1.4.9",
"@alicloud/tea-xml": "0.0.3"
}
},
"node_modules/@alicloud/openapi-client/node_modules/@alicloud/tea-util": {
"version": "1.4.9",
"resolved": "https://registry.npmjs.org/@alicloud/tea-util/-/tea-util-1.4.9.tgz",
"integrity": "sha512-S0wz76rGtoPKskQtRTGqeuqBHFj8BqUn0Vh+glXKun2/9UpaaaWmuJwcmtImk6bJZfLYEShDF/kxDmDJoNYiTw==",
"dependencies": {
"@alicloud/tea-typescript": "^1.5.1",
"kitx": "^2.0.0"
}
},
"node_modules/@alicloud/openapi-core": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@alicloud/openapi-core/-/openapi-core-1.0.5.tgz",
"integrity": "sha512-ed4EKyqHjb9zwrXUs6IRthha/pRn3OUoOcUKuhYu4tllp0RpidA+JYswsweN6sh26H0WIs/LB6nzJEOvh1d3fg==",
"hasInstallScript": true,
"dependencies": {
"@alicloud/credentials": "latest",
"@alicloud/gateway-pop": "0.0.6",
"@alicloud/gateway-spi": "^0.0.8",
"@darabonba/typescript": "^1.0.2"
}
},
"node_modules/@alicloud/openapi-util": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@alicloud/openapi-util/-/openapi-util-0.3.2.tgz",
"integrity": "sha512-EC2JvxdcOgMlBAEG0+joOh2IB1um8CPz9EdYuRfTfd1uP8Yc9D8QRUWVGjP6scnj6fWSOaHFlit9H6PrJSyFow==",
"dependencies": {
"@alicloud/tea-typescript": "^1.7.1",
"@alicloud/tea-util": "^1.3.0",
"kitx": "^2.1.0",
"sm3": "^1.0.3"
}
},
"node_modules/@alicloud/tea-typescript": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@alicloud/tea-typescript/-/tea-typescript-1.8.0.tgz",
"integrity": "sha512-CWXWaquauJf0sW30mgJRVu9aaXyBth5uMBCUc+5vKTK1zlgf3hIqRUjJZbjlwHwQ5y9anwcu18r48nOZb7l2QQ==",
"dependencies": {
"@types/node": "^12.0.2",
"httpx": "^2.2.6"
}
},
"node_modules/@alicloud/tea-util": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/@alicloud/tea-util/-/tea-util-1.4.10.tgz",
"integrity": "sha512-VEsXWP2dlJLvsY2THj+sH++zwxQRz3Y5BQ8EkfnFems36RkngQKYOLsoto5nR6ej1Gf6I+0IOgBXrkRdpNCQ1g==",
"dependencies": {
"@alicloud/tea-typescript": "^1.5.1",
"@darabonba/typescript": "^1.0.0",
"kitx": "^2.0.0"
}
},
"node_modules/@alicloud/tea-xml": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@alicloud/tea-xml/-/tea-xml-0.0.3.tgz",
"integrity": "sha512-+/9GliugjrLglsXVrd1D80EqqKgGpyA0eQ6+1ZdUOYCaRguaSwz44trX3PaxPu/HhIPJg9PsGQQ3cSLXWZjbAA==",
"dependencies": {
"@alicloud/tea-typescript": "^1",
"@types/xml2js": "^0.4.5",
"xml2js": "^0.6.0"
}
},
"node_modules/@apidevtools/json-schema-ref-parser": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
@@ -61,6 +242,19 @@
"openapi-types": ">=7"
}
},
"node_modules/@darabonba/typescript": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@darabonba/typescript/-/typescript-1.0.3.tgz",
"integrity": "sha512-/y2y6wf5TsxD7pCPIm0OvTC+5qV0Tk7HQYxwpIuWRLXQLB0CRDvr6qk4bR6rTLO/JglJa8z2uCGZsaLYpQNqFQ==",
"dependencies": {
"@alicloud/tea-typescript": "^1.5.1",
"httpx": "^2.3.2",
"lodash": "^4.17.21",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
"xml2js": "^0.6.2"
}
},
"node_modules/@jsdevtools/ono": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
@@ -77,6 +271,19 @@
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
},
"node_modules/@types/node": {
"version": "12.20.55",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
"integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="
},
"node_modules/@types/xml2js": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz",
"integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -129,38 +336,26 @@
"integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
},
"node_modules/body-parser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": {
"bytes": "^3.1.2",
"content-type": "^1.0.5",
"debug": "^4.4.0",
"http-errors": "^2.0.0",
"iconv-lite": "^0.6.3",
"on-finished": "^2.4.1",
"qs": "^6.14.0",
"raw-body": "^3.0.0",
"type-is": "^2.0.0"
"bytes": "3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/body-parser/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/body-parser/node_modules/depd": {
@@ -171,6 +366,15 @@
"node": ">= 0.8"
}
},
"node_modules/body-parser/node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/body-parser/node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -191,38 +395,6 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/body-parser/node_modules/media-typer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/body-parser/node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/body-parser/node_modules/mime-types": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
"dependencies": {
"mime-db": "^1.54.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/body-parser/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/body-parser/node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -235,11 +407,11 @@
}
},
"node_modules/body-parser/node_modules/qs": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.1.0"
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -261,19 +433,6 @@
"node": ">= 0.8"
}
},
"node_modules/body-parser/node_modules/type-is": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
"dependencies": {
"content-type": "^1.0.5",
"media-typer": "^1.1.0",
"mime-types": "^3.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@@ -773,12 +932,50 @@
"node": ">= 0.6"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"node_modules/httpx": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/httpx/-/httpx-2.3.3.tgz",
"integrity": "sha512-k1qv94u1b6e+XKCxVbLgYlOypVP9MPGpnN5G/vxFf6tDO4V3xpz3d6FUOY/s8NtPgaq5RBVVgSB+7IHpVxMYzw==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
"@types/node": "^20",
"debug": "^4.1.1"
}
},
"node_modules/httpx/node_modules/@types/node": {
"version": "20.19.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.17.tgz",
"integrity": "sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/httpx/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/httpx/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
@@ -799,6 +996,11 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
},
"node_modules/ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -868,6 +1070,27 @@
"safe-buffer": "^5.0.1"
}
},
"node_modules/kitx": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/kitx/-/kitx-2.2.0.tgz",
"integrity": "sha512-tBMwe6AALTBQJb0woQDD40734NKzb0Kzi3k7wQj9ar3AbP9oqhoVrdXPh7rk2r00/glIgd0YbToIUJsnxWMiIg==",
"dependencies": {
"@types/node": "^22.5.4"
}
},
"node_modules/kitx/node_modules/@types/node": {
"version": "22.18.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz",
"integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@@ -1014,6 +1237,25 @@
"node": "*"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"engines": {
"node": "*"
}
},
"node_modules/moment-timezone": {
"version": "0.5.48",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz",
"integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==",
"dependencies": {
"moment": "^2.29.4"
},
"engines": {
"node": "*"
}
},
"node_modules/morgan": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
@@ -1189,17 +1431,17 @@
}
},
"node_modules/raw-body": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz",
"integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==",
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.7.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.10"
"node": ">= 0.8"
}
},
"node_modules/raw-body/node_modules/depd": {
@@ -1225,21 +1467,6 @@
"node": ">= 0.8"
}
},
"node_modules/raw-body/node_modules/iconv-lite": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/raw-body/node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -1268,6 +1495,11 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
@@ -1394,6 +1626,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/sm3": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sm3/-/sm3-1.0.3.tgz",
"integrity": "sha512-KyFkIfr8QBlFG3uc3NaljaXdYcsbRy1KrSfc4tsQV8jW68jAktGeOcifu530Vx/5LC+PULHT0Rv8LiI8Gw+c1g=="
},
"node_modules/sqlstring": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
@@ -1482,6 +1719,11 @@
"node": ">= 0.6"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -1519,6 +1761,26 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/xml2js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
"integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"engines": {
"node": ">=4.0"
}
},
"node_modules/yaml": {
"version": "2.0.0-1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",

View File

@@ -6,8 +6,10 @@
"start": "node ./bin/www"
},
"dependencies": {
"@alicloud/dysmsapi20170525": "^4.1.1",
"@alicloud/openapi-client": "^0.4.15",
"bcryptjs": "^2.4.3",
"body-parser": "^2.2.0",
"body-parser": "^1.20.2",
"cookie-parser": "~1.4.4",
"cors": "^2.8.5",
"debug": "~2.6.9",

View File

@@ -1,13 +0,0 @@
<html>
<head>
<title>Express</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<h1>Express</h1>
<p>Welcome to Express</p>
</body>
</html>

View File

@@ -1,8 +0,0 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}

View File

@@ -143,7 +143,6 @@ router.post('/register', async (req, res) => {
router.post('/login', async (req, res) => {
console.log(123456)
try {
const db = getDB();
const {username, password, captchaId, captchaText} = req.body;

View File

@@ -1,6 +0,0 @@
var express = require('express');
var router = express.Router();
module.exports = router;

340
routes/sms.js Normal file
View File

@@ -0,0 +1,340 @@
const express = require('express')
const router = express.Router()
const { getDB } = require('../database')
const Dysmsapi20170525 = require('@alicloud/dysmsapi20170525')
const OpenApi = require('@alicloud/openapi-client')
const { Config } = require('@alicloud/openapi-client')
/**
* @swagger
* tags:
* name: SMS
* description: 短信验证码相关接口
*/
/**
* @swagger
* components:
* schemas:
* SMSVerification:
* type: object
* properties:
* phone:
* type: string
* description: 手机号码
* code:
* type: string
* description: 验证码
*/
// 阿里云短信配置
const config = new Config({
// 您的AccessKey ID
accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID || 'your_access_key_id',
// 您的AccessKey Secret
accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET || 'your_access_key_secret',
// 访问的域名
endpoint: 'dysmsapi.aliyuncs.com'
})
// 创建短信客户端
const client = new Dysmsapi20170525.default(config)
// 短信模板配置
const SMS_CONFIG = {
signName: process.env.ALIYUN_SMS_SIGN_NAME || '您的签名', // 短信签名
templateCode: process.env.ALIYUN_SMS_TEMPLATE_CODE || 'SMS_XXXXXX', // 短信模板CODE
// 开发环境标识
isDevelopment: process.env.NODE_ENV !== 'production'
}
// 存储验证码的内存对象生产环境建议使用Redis
const smsCodeStore = new Map()
// 验证码有效期5分钟
const CODE_EXPIRE_TIME = 5 * 60 * 1000
// 最大尝试次数
const MAX_ATTEMPTS = 3
// 发送频率限制60秒
const SEND_INTERVAL = 60 * 1000
/**
* 生成6位数字验证码
* @returns {string} 验证码
*/
function generateSMSCode() {
return Math.floor(100000 + Math.random() * 900000).toString();
}
/**
* @swagger
* /api/sms/send:
* post:
* summary: 发送短信验证码
* tags: [SMS]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - phone
* properties:
* phone:
* type: string
* description: 手机号码
* responses:
* 200:
* description: 验证码发送成功
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* example: true
* message:
* type: string
* example: 验证码发送成功
* 400:
* description: 参数错误或发送频率限制
* 500:
* description: 服务器错误
*/
router.post('/send', async (req, res) => {
try {
const { phone } = req.body
console.log(phone)
// 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/
if (!phoneRegex.test(phone)) {
return res.json({
success: false,
message: '手机号格式不正确'
})
}
// 检查发送频率限制
const lastSendTime = smsCodeStore.get(`last_send_${phone}`)
if (lastSendTime && Date.now() - lastSendTime < SEND_INTERVAL) {
const remainingTime = Math.ceil((SEND_INTERVAL - (Date.now() - lastSendTime)) / 1000)
return res.json({
success: false,
message: `请等待${remainingTime}秒后再发送`
})
}
// 生成6位数字验证码
const code = Math.random().toString().slice(-6)
// 存储验证码信息
smsCodeStore.set(phone, {
code,
timestamp: Date.now(),
attempts: 0
})
// 记录发送时间
smsCodeStore.set(`last_send_${phone}`, Date.now())
// 生产环境发送真实短信
try {
console.log(code);
res.json({
success: true,
message: '验证码发送成功'
})
return
const sendSmsRequest = new Dysmsapi20170525.SendSmsRequest({
phoneNumbers: phone,
signName: SMS_CONFIG.signName,
templateCode: SMS_CONFIG.templateCode,
templateParam: JSON.stringify({ code })
})
const response = await client.sendSms(sendSmsRequest)
console.log(response.body);
if (response.body.code === 'OK') {
res.json({
success: true,
message: '验证码发送成功'
})
} else {
console.error('阿里云短信发送失败:', response.body)
res.json({
success: false,
message: '发送失败,请稍后重试'
})
}
} catch (smsError) {
console.error('阿里云短信API调用失败:', smsError)
res.json({
success: false,
message: '发送失败,请稍后重试'
})
}
} catch (error) {
console.error('发送短信验证码失败:', error)
res.status(500).json({
success: false,
message: '发送失败,请稍后重试'
})
}
});
/**
* @swagger
* /api/sms/verify:
* post:
* summary: 验证短信验证码
* tags: [SMS]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - phone
* - code
* properties:
* phone:
* type: string
* description: 手机号码
* code:
* type: string
* description: 验证码
* responses:
* 200:
* description: 验证码验证成功
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* example: true
* message:
* type: string
* example: 手机号验证成功
* data:
* type: object
* properties:
* phone:
* type: string
* verified:
* type: boolean
* 400:
* description: 参数错误或验证码错误
* 500:
* description: 服务器错误
*/
router.post('/verify', async (req, res) => {
try {
const { phone, code } = req.body;
if (!phone || !code) {
return res.status(400).json({ success: false, message: '手机号和验证码不能为空' });
}
const storedData = smsCodeStore.get(phone);
if (!storedData) {
return res.status(400).json({ success: false, message: '验证码不存在或已过期' });
}
// 检查验证码是否过期5分钟
if (Date.now() - storedData.timestamp > 300000) {
smsCodeStore.delete(phone);
return res.status(400).json({ success: false, message: '验证码已过期' });
}
// 检查尝试次数最多3次
if (storedData.attempts >= 3) {
smsCodeStore.delete(phone);
return res.status(400).json({ success: false, message: '验证码错误次数过多,请重新获取' });
}
// 验证验证码
if (storedData.code !== code) {
storedData.attempts++;
smsCodeStore.set(phone, storedData);
return res.status(400).json({
success: false,
message: `验证码错误,还可尝试${3 - storedData.attempts}`
});
}
// 验证成功,删除验证码
smsCodeStore.delete(phone);
smsCodeStore.delete(`time_${phone}`);
res.json({
success: true,
message: '手机号验证成功',
data: {
phone: phone,
verified: true
}
});
} catch (error) {
console.error('验证短信验证码错误:', error);
res.status(500).json({ success: false, message: '验证失败' });
}
});
/**
* 导出验证手机号的函数供其他模块使用
* @param {string} phone 手机号
* @param {string} code 验证码
* @returns {boolean} 验证结果
*/
function verifySMSCode(phone, code) {
const storedData = smsCodeStore.get(phone);
if (!storedData) {
return false;
}
// 检查是否过期
if (Date.now() - storedData.timestamp > 300000) {
smsCodeStore.delete(phone);
return false;
}
// 检查尝试次数
if (storedData.attempts >= 3) {
smsCodeStore.delete(phone);
return false;
}
// 验证验证码
if (storedData.code === code) {
smsCodeStore.delete(phone);
smsCodeStore.delete(`time_${phone}`);
return true;
}
return false;
}
// 清理过期验证码的定时任务
setInterval(() => {
const now = Date.now();
for (const [key, value] of smsCodeStore.entries()) {
if (key.startsWith('time_')) continue;
if (value.timestamp && now - value.timestamp > 300000) {
smsCodeStore.delete(key);
smsCodeStore.delete(`time_${key}`);
}
}
}, 60000); // 每分钟清理一次
module.exports = router;
module.exports.verifySMSCode = verifySMSCode;

View File

@@ -1,9 +0,0 @@
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/',function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;