后端加入Redis、旋转图片验证接口
This commit is contained in:
@@ -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
286
Server/pnpm-lock.yaml
generated
@@ -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'}
|
||||||
|
|||||||
41
Server/src/APIs/CheckCaptcha.ts
Normal file
41
Server/src/APIs/CheckCaptcha.ts
Normal 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;
|
||||||
36
Server/src/APIs/GetCaptcha.ts
Normal file
36
Server/src/APIs/GetCaptcha.ts
Normal 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;
|
||||||
43
Server/src/Plugs/RedisConnection.ts
Normal file
43
Server/src/Plugs/RedisConnection.ts
Normal 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();
|
||||||
114
Server/src/Plugs/Service/captchaSession.ts
Normal file
114
Server/src/Plugs/Service/captchaSession.ts
Normal 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;
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
BIN
Server/src/assets/captchaImgs/1.jpg
Normal file
BIN
Server/src/assets/captchaImgs/1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
BIN
Server/src/assets/captchaImgs/2.jpg
Normal file
BIN
Server/src/assets/captchaImgs/2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
BIN
Server/src/assets/captchaImgs/3.jpg
Normal file
BIN
Server/src/assets/captchaImgs/3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
BIN
Server/src/assets/captchaImgs/4.jpg
Normal file
BIN
Server/src/assets/captchaImgs/4.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
BIN
Server/src/assets/captchaImgs/5.jpg
Normal file
BIN
Server/src/assets/captchaImgs/5.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
BIN
Server/src/assets/captchaImgs/6.jpg
Normal file
BIN
Server/src/assets/captchaImgs/6.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user