后端加入Redis、旋转图片验证接口

This commit is contained in:
2024-08-30 21:34:24 +08:00
parent a69cd3af61
commit 29f2c09a69
15 changed files with 551 additions and 2 deletions

View File

@@ -23,6 +23,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.19.2", "express": "^4.19.2",
"ioredis": "^5.4.1", "ioredis": "^5.4.1",
"mysql2": "^3.9.7" "mysql2": "^3.9.7",
"sharp": "^0.33.5"
} }
} }

286
Server/pnpm-lock.yaml generated
View File

@@ -23,6 +23,9 @@ dependencies:
mysql2: mysql2:
specifier: ^3.9.7 specifier: ^3.9.7
version: 3.9.7 version: 3.9.7
sharp:
specifier: ^0.33.5
version: 0.33.5
devDependencies: devDependencies:
'@types/cors': '@types/cors':
@@ -50,6 +53,206 @@ packages:
'@jridgewell/trace-mapping': 0.3.9 '@jridgewell/trace-mapping': 0.3.9
dev: true dev: true
/@emnapi/runtime@1.2.0:
resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==}
requiresBuild: true
dependencies:
tslib: 2.7.0
dev: false
optional: true
/@img/sharp-darwin-arm64@0.33.5:
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.0.4
dev: false
optional: true
/@img/sharp-darwin-x64@0.33.5:
resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [darwin]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.0.4
dev: false
optional: true
/@img/sharp-libvips-darwin-arm64@1.0.4:
resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-darwin-x64@1.0.4:
resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-arm64@1.0.4:
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-arm@1.0.5:
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
cpu: [arm]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-s390x@1.0.4:
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-x64@1.0.4:
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
cpu: [x64]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linuxmusl-arm64@1.0.4:
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
cpu: [arm64]
os: [linux]
libc: [musl]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linuxmusl-x64@1.0.4:
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
cpu: [x64]
os: [linux]
libc: [musl]
requiresBuild: true
dev: false
optional: true
/@img/sharp-linux-arm64@0.33.5:
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.0.4
dev: false
optional: true
/@img/sharp-linux-arm@0.33.5:
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
libc: [glibc]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.0.5
dev: false
optional: true
/@img/sharp-linux-s390x@0.33.5:
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.0.4
dev: false
optional: true
/@img/sharp-linux-x64@0.33.5:
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [glibc]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.0.4
dev: false
optional: true
/@img/sharp-linuxmusl-arm64@0.33.5:
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [musl]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
dev: false
optional: true
/@img/sharp-linuxmusl-x64@0.33.5:
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [musl]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
dev: false
optional: true
/@img/sharp-wasm32@0.33.5:
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [wasm32]
requiresBuild: true
dependencies:
'@emnapi/runtime': 1.2.0
dev: false
optional: true
/@img/sharp-win32-ia32@0.33.5:
resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@img/sharp-win32-x64@0.33.5:
resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@ioredis/commands@1.2.0: /@ioredis/commands@1.2.0:
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
dev: false dev: false
@@ -248,6 +451,32 @@ packages:
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: false dev: false
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/color-string@1.9.1:
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: false
/color@4.2.3:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
engines: {node: '>=12.5.0'}
dependencies:
color-convert: 2.0.1
color-string: 1.9.1
dev: false
/combined-stream@1.0.8: /combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -340,6 +569,11 @@ packages:
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
dev: false dev: false
/detect-libc@2.0.3:
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
engines: {node: '>=8'}
dev: false
/diff@4.0.2: /diff@4.0.2:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'} engines: {node: '>=0.3.1'}
@@ -559,6 +793,10 @@ packages:
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
dev: false dev: false
/is-arrayish@0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: false
/is-property@1.0.2: /is-property@1.0.2:
resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
dev: false dev: false
@@ -738,6 +976,12 @@ packages:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false dev: false
/semver@7.6.3:
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
hasBin: true
dev: false
/send@0.18.0: /send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -791,6 +1035,36 @@ packages:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
dev: false dev: false
/sharp@0.33.5:
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
requiresBuild: true
dependencies:
color: 4.2.3
detect-libc: 2.0.3
semver: 7.6.3
optionalDependencies:
'@img/sharp-darwin-arm64': 0.33.5
'@img/sharp-darwin-x64': 0.33.5
'@img/sharp-libvips-darwin-arm64': 1.0.4
'@img/sharp-libvips-darwin-x64': 1.0.4
'@img/sharp-libvips-linux-arm': 1.0.5
'@img/sharp-libvips-linux-arm64': 1.0.4
'@img/sharp-libvips-linux-s390x': 1.0.4
'@img/sharp-libvips-linux-x64': 1.0.4
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
'@img/sharp-linux-arm': 0.33.5
'@img/sharp-linux-arm64': 0.33.5
'@img/sharp-linux-s390x': 0.33.5
'@img/sharp-linux-x64': 0.33.5
'@img/sharp-linuxmusl-arm64': 0.33.5
'@img/sharp-linuxmusl-x64': 0.33.5
'@img/sharp-wasm32': 0.33.5
'@img/sharp-win32-ia32': 0.33.5
'@img/sharp-win32-x64': 0.33.5
dev: false
/side-channel@1.0.6: /side-channel@1.0.6:
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -801,6 +1075,12 @@ packages:
object-inspect: 1.13.1 object-inspect: 1.13.1
dev: false dev: false
/simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
dependencies:
is-arrayish: 0.3.2
dev: false
/sqlstring@2.3.3: /sqlstring@2.3.3:
resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -851,6 +1131,12 @@ packages:
yn: 3.1.1 yn: 3.1.1
dev: true dev: true
/tslib@2.7.0:
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
requiresBuild: true
dev: false
optional: true
/type-is@1.6.18: /type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}

View File

@@ -0,0 +1,41 @@
import { API } from "../Plugs/API/API";
import ServerStdResponse from "../ServerStdResponse";
import captchaSession from "../Plugs/Service/captchaSession";
// 检查人机验证
class CheckCaptcha extends API {
constructor() {
super('POST', '/checkCaptcha');
}
public async onRequset(data: any, res: any) {
let { session, rotateDeg } = data;
if (!session || !rotateDeg) {
return res.json(ServerStdResponse.PARAMS_MISSING);
}
switch (await captchaSession.check(session, rotateDeg)) {
case 0:
// 验证码已过期或服务器错误
res.json(ServerStdResponse.CAPTCHA.NOTFOUND);
break;
case 1:
// 验证通过
res.json(ServerStdResponse.OK);
break;
case -1:
// 超过最大尝试次数
res.json(ServerStdResponse.CAPTCHA.MAX_TRY_COUNT);
break;
case -2:
// 角度不正确
res.json(ServerStdResponse.CAPTCHA.NOTRIGHT);
break;
default:
// 未知错误
res.json(ServerStdResponse.SERVER_ERROR);
break;
}
}
}
export default CheckCaptcha;

View File

@@ -0,0 +1,36 @@
import fs from "fs";
import { API } from "../Plugs/API/API";
import ServerStdResponse from "../ServerStdResponse";
import captchaSession from "../Plugs/Service/captchaSession";
import path from "path";
import sharp from "sharp";
import crypto from 'crypto'
// 获取人机验证图片及标识符
class GetCaptcha extends API {
constructor() {
super('GET', '/captcha');
}
public async onRequset(data: any, res: any) {
const imgsPath = path.join(__dirname, '../assets/captchaImgs');
const fileList = fs.readdirSync(imgsPath)
const imgPath = path.join(imgsPath, fileList[Math.floor(Math.random() * fileList.length)]);
const rotateDeg = Math.floor(Math.random() * 240) + 60;
const img = Buffer.from(await sharp(imgPath).rotate(-rotateDeg).toBuffer()).toString('base64')
const session = crypto.createHash('md5').update(`${Math.random()} ${Date.now()}`).digest('hex');
if (await captchaSession.add(session, rotateDeg)) {
return res.json({
...ServerStdResponse.OK, data: {
img: img,
session: session,
imgPreStr: 'data:image/jpeg;base64,'
}
});
} else {
return res.json(ServerStdResponse.SERVER_ERROR)
}
}
}
export default GetCaptcha;

View File

@@ -0,0 +1,43 @@
import Redis from 'ioredis';
import config from '../config';
import Logger from './Logger';
class RedisConnection {
private pool?: Redis
private logger = new Logger('Redis')
constructor() {
try {
this.pool = new Redis({
port: config.redis.port,
host: config.redis.host,
password: config.redis.password,
maxRetriesPerRequest: 10,
});
this.logger.info('数据库连接池已创建')
} catch (error) {
this.logger.error('数据库连接池创建失败:' + error)
}
setTimeout(async () => {
if(this.pool == undefined)
return;
try {
let res = await this.pool.set('redis_test', '1');
if (res)
this.logger.info('数据库测试成功')
else
throw new Error('返回值错误')
} catch (error) {
this.logger.error('数据库测试失败:' + error)
}
}, 10);
}
public getPool(): Redis {
return <Redis>this.pool;
}
}
const redisConnection = new RedisConnection();
export default redisConnection.getPool();

View File

@@ -0,0 +1,114 @@
import Logger from '../Logger';
import RedisConnection from '../RedisConnection';
class _captchaSession {
private logger = new Logger('Service][captchaSession');
private AllowMaxTryCount: number = 5;
private AllowMaxAngleDiff: number = 8;
private ExpriedTimeSec: number = 60;
private RedisCommonKey: string = 'Service:captchaSession:';
constructor() {
this.logger.info('旋转图像验证服务已启动');
}
private async get(session: string) {
try {
const result = await RedisConnection.get(this.RedisCommonKey + session);
if(result === null)
return;
return JSON.parse(result);
} catch (error) {
this.logger.error(`获取session[${session}]时发生错误:${error}`);
return;
}
}
private async remove(session: string) {
try {
await RedisConnection.del(this.RedisCommonKey + session);
} catch (error) {
this.logger.error(`删除session[${session}]失败`);
}
}
/**
*
* @param session 验证会话标识符
* @param rotateDeg 图片旋转角度
* @returns true存储成功 false存储失败
*/
public async add(session: string, rotateDeg: number): Promise<boolean> {
const result = {
rotateDeg: rotateDeg,
tryCount: 0,
isPassed: false
}
try {
const res = await RedisConnection.set(this.RedisCommonKey + session, JSON.stringify(result));
if(res && res === 'OK') {
RedisConnection.expire(this.RedisCommonKey + session, this.ExpriedTimeSec);
this.logger.info(`session[${session}]及角度[${rotateDeg}]已存储`);
return true;
}
this.logger.error(`session[${session}]及角度[${rotateDeg}]存储失败`);
return false;
} catch (error) {
this.logger.error(`session[${session}]及角度[${rotateDeg}]存储失败:${error}`);
return false;
}
}
/**
*
* @param session 验证会话标识符
* @returns true已验证过期 false未通过
*/
public async isPassed(session: string): Promise<boolean> {
const result = await this.get(session);
if(!result)
return false;
if(result.isPassed)
this.remove(session);
return result.isPassed;
}
/**
*
* @param session 验证会话标识符
* @param rotateDeg 图片旋转角度
* @returns 0验证已过期或服务器错误 1通过验证 -1超过最大允许尝试次数 -2角度差异过大
*/
public async check(session: string, rotateDeg: number): Promise<number> {
try {
let result = await this.get(session);
if(!result){
return 0;
}
if(result.isPassed){
this.logger.info(`session[${session}]已通过验证,无需重复验证`);
return 1;
}
if(Math.abs(result.rotateDeg - rotateDeg) <= this.AllowMaxAngleDiff) {
result.isPassed = true;
await RedisConnection.del(this.RedisCommonKey + session);
await RedisConnection.set(this.RedisCommonKey + session, JSON.stringify(result));
RedisConnection.expire(this.RedisCommonKey + session, this.ExpriedTimeSec);
return 1;
}
result.tryCount++;
if(result.tryCount >= this.AllowMaxTryCount) {
this.remove(session);
return -1;
}
RedisConnection.set(this.RedisCommonKey + session, JSON.stringify(result));
return -2;
} catch (error) {
this.logger.error(`检查session[${session}]时发生错误:${error}`);
return 0;
}
}
}
const captchaSession = new _captchaSession();
export default captchaSession;

View File

@@ -2,11 +2,17 @@ import Logger from "../Plugs/Logger";
import { APILoader } from "../Plugs/API/APILoader"; import { APILoader } from "../Plugs/API/APILoader";
import config from "../config"; import config from "../config";
// 加载Plugs
import '../Plugs/Service/captchaSession'
// 加载API
import GetTest from "../APIs/GetTest"; import GetTest from "../APIs/GetTest";
import GetResourceList from "../APIs/GetResourceList"; import GetResourceList from "../APIs/GetResourceList";
import GetBlogList from "../APIs/GetBlogList"; import GetBlogList from "../APIs/GetBlogList";
import GetBlogContent from "../APIs/GetBlogContent"; import GetBlogContent from "../APIs/GetBlogContent";
import BlogLike from "../APIs/BlogLike"; import BlogLike from "../APIs/BlogLike";
import GetCaptcha from "../APIs/GetCaptcha";
import CheckCaptcha from "../APIs/CheckCaptcha";
class Server { class Server {
private logger = new Logger('Server'); private logger = new Logger('Server');
@@ -18,12 +24,14 @@ class Server {
} }
public async start() { public async start() {
// 加载前台API // 加载API
this.apiLoader.add(GetTest); this.apiLoader.add(GetTest);
this.apiLoader.add(GetResourceList); this.apiLoader.add(GetResourceList);
this.apiLoader.add(GetBlogList); this.apiLoader.add(GetBlogList);
this.apiLoader.add(GetBlogContent); this.apiLoader.add(GetBlogContent);
this.apiLoader.add(BlogLike); this.apiLoader.add(BlogLike);
this.apiLoader.add(GetCaptcha);
this.apiLoader.add(CheckCaptcha);
this.apiLoader.start(config.apiPort); this.apiLoader.start(config.apiPort);
} }

View File

@@ -29,6 +29,20 @@ const ServerStdResponse = {
message: 'Blog not found' message: 'Blog not found'
} }
}, },
CAPTCHA: {
NOTFOUND: {
code: -5000,
message: 'captcha session not found'
},
MAX_TRY_COUNT: {
code: -5001,
message: 'captcha session try max count'
},
NOTRIGHT: {
code: -5002,
message: 'captcha is not right, please try again'
}
}
} as const; } as const;
export default ServerStdResponse; export default ServerStdResponse;

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@@ -7,6 +7,12 @@ const config = {
password: 'Shi15023847146' password: 'Shi15023847146'
// password: '245565' // password: '245565'
}, },
redis: {
port: 6379,
host: 'localhost',
password: ''
// password: 'jhkdjhkjdhsIUTYURTU_f7EJZJ'
},
authToken: '17e50223f4a545ec9e36ebf08e2f71bb', authToken: '17e50223f4a545ec9e36ebf08e2f71bb',
adminToken: '3a6f71412f9e48b9bbbd056aa7eb5467', adminToken: '3a6f71412f9e48b9bbbd056aa7eb5467',
apiPort: 23500, apiPort: 23500,