diff --git a/back/api/auth.ts b/back/api/auth.ts index 79e09572..01f1cd99 100644 --- a/back/api/auth.ts +++ b/back/api/auth.ts @@ -3,66 +3,28 @@ import { Container } from 'typedi'; import { Logger } from 'winston'; import * as fs from 'fs'; import config from '../config'; -import jwt from 'jsonwebtoken'; -import { createRandomString } from '../config/util'; -import crypto from 'crypto'; +import { getNetIp } from '../config/util'; +import AuthService from '../services/auth'; +import { celebrate, Joi } from 'celebrate'; const route = Router(); export default (app: Router) => { app.use('/', route); route.post( '/login', + celebrate({ + body: Joi.object({ + username: Joi.string().required(), + password: Joi.string().required(), + }), + }), async (req: Request, res: Response, next: NextFunction) => { const logger: Logger = Container.get('logger'); try { - let username = req.body.username; - let password = req.body.password; - fs.readFile(config.authConfigFile, 'utf8', function (err, data) { - if (err) console.log(err); - const authInfo = JSON.parse(data); - if (username && password) { - if ( - authInfo.username === 'admin' && - authInfo.password === 'adminadmin' - ) { - const newPassword = createRandomString(16, 22); - fs.writeFileSync( - config.authConfigFile, - JSON.stringify({ - username: authInfo.username, - password: newPassword, - }), - ); - return res.send({ - code: 100, - message: '已初始化密码,请前往auth.json查看并重新登录', - }); - } - if ( - username == authInfo.username && - password == authInfo.password - ) { - const data = createRandomString(50, 100); - let token = jwt.sign({ data }, config.secret as any, { - expiresIn: 60 * 60 * 24 * 3, - algorithm: 'HS384', - }); - fs.writeFileSync( - config.authConfigFile, - JSON.stringify({ - username: authInfo.username, - password: authInfo.password, - token, - }), - ); - res.send({ code: 200, token }); - } else { - res.send({ code: 400, message: config.authError }); - } - } else { - res.send({ err: 400, message: '请输入用户名密码!' }); - } - }); + const authService = Container.get(AuthService); + const ipInfo = await getNetIp(req); + const data = await authService.login({ ...req.body, ...ipInfo }); + return res.send(data); } catch (e) { logger.error('🔥 error: %o', e); return next(e); @@ -81,8 +43,8 @@ export default (app: Router) => { fs.writeFileSync( config.authConfigFile, JSON.stringify({ - username: authInfo.username, - password: authInfo.password, + ...authInfo, + token: '', }), ); res.send({ code: 200 }); @@ -99,10 +61,15 @@ export default (app: Router) => { async (req: Request, res: Response, next: NextFunction) => { const logger: Logger = Container.get('logger'); try { - fs.writeFile(config.authConfigFile, JSON.stringify(req.body), (err) => { - if (err) console.log(err); - res.send({ code: 200, message: '更新成功' }); - }); + const content = fs.readFileSync(config.authConfigFile, 'utf8'); + fs.writeFile( + config.authConfigFile, + JSON.stringify({ ...JSON.parse(content || '{}'), ...req.body }), + (err) => { + if (err) console.log(err); + res.send({ code: 200, message: '更新成功' }); + }, + ); } catch (e) { logger.error('🔥 error: %o', e); return next(e); diff --git a/back/config/util.ts b/back/config/util.ts index 6d747449..7ca85a8f 100644 --- a/back/config/util.ts +++ b/back/config/util.ts @@ -1,5 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; +import got from 'got'; export function getFileContentByName(fileName: string) { if (fs.existsSync(fileName)) { @@ -119,3 +120,52 @@ export function getToken(req: any) { } return ''; } + +export async function getNetIp(req: any) { + const ipArray = [ + ...new Set([ + ...(req.headers['x-real-ip'] || '').split(','), + ...(req.headers['x-forwarded-for'] || '').split(','), + req.ip, + ...req.ips, + req.socket.remoteAddress, + ]), + ]; + let ip = ipArray[0]; + console.log(ipArray); + if (ipArray.length > 1) { + for (let i = 0; i < ipArray.length; i++) { + const ipNumArray = ipArray[i].split('.'); + const tmp = ipNumArray[0] + '.' + ipNumArray[1]; + if ( + tmp === '192.168' || + (ipNumArray[0] === '172' && + ipNumArray[1] >= 16 && + ipNumArray[1] <= 32) || + tmp === '10.7' || + tmp === '127.0' + ) { + continue; + } + ip = ipArray[i]; + } + } + ip = ip.substr(ip.lastIndexOf(':') + 1, ip.length); + if (ip.includes('127.0') || ip.includes('192.168') || ip.includes('10.7')) { + ip = ''; + } + + try { + const { data } = await got + .get( + `https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=${ip}&co=&resource_id=6006&t=1555898284898&ie=utf8&oe=utf8&format=json&tn=baidu`, + ) + .json(); + return { address: data[0].location, ip }; + } catch (error) { + const { country, regionName, city } = await got + .get(`http://ip-api.com/json/${ip}?lang=zh-CN`) + .json(); + return { address: `${country} ${regionName} ${city}`, ip }; + } +} diff --git a/back/services/auth.ts b/back/services/auth.ts new file mode 100644 index 00000000..ac8fba81 --- /dev/null +++ b/back/services/auth.ts @@ -0,0 +1,103 @@ +import { Service, Inject } from 'typedi'; +import winston from 'winston'; +import { createRandomString, getFileContentByName } from '../config/util'; +import config from '../config'; +import * as fs from 'fs'; +import _ from 'lodash'; +import jwt from 'jsonwebtoken'; + +@Service() +export default class AuthService { + constructor(@Inject('logger') private logger: winston.Logger) {} + + public async login(payloads: { + username: string; + password: string; + ip: string; + address: string; + }): Promise { + if (!fs.existsSync(config.authConfigFile)) { + return this.initAuthInfo(); + } + + let { username, password, ip, address } = payloads; + const content = fs.readFileSync(config.authConfigFile, 'utf8'); + const timestamp = Date.now(); + if (content) { + const { + username: cUsername, + password: cPassword, + retries = 0, + lastlogon, + lastip, + lastaddr, + } = JSON.parse(content); + if ( + (cUsername === 'admin' && cPassword === 'adminadmin') || + !cUsername || + !cPassword + ) { + return this.initAuthInfo(); + } + if (username === cUsername && password === cPassword) { + const data = createRandomString(50, 100); + let token = jwt.sign({ data }, config.secret as any, { + expiresIn: 60 * 60 * 24 * 3, + algorithm: 'HS384', + }); + fs.writeFileSync( + config.authConfigFile, + JSON.stringify({ + ...JSON.parse(content), + token, + lastlogon: timestamp, + retries: 0, + lastip: ip, + lastaddr: address, + }), + ); + return { code: 200, data: { token, lastip, lastaddr, lastlogon } }; + } else { + if ( + retries > 2 && + Date.now() - lastlogon < Math.pow(3, retries) * 1000 + ) { + return { + code: 400, + message: `失败次数过多,请${Math.round( + (Math.pow(3, retries) * 1000 - Date.now() + lastlogon) / 1000, + )}秒后重试`, + }; + } + fs.writeFileSync( + config.authConfigFile, + JSON.stringify({ + ...JSON.parse(content), + retries: retries + 1, + lastlogon: timestamp, + ip, + address, + }), + ); + return { code: 400, message: config.authError }; + } + } else { + return this.initAuthInfo(); + } + } + + private initAuthInfo() { + const newPassword = createRandomString(16, 22); + fs.writeFileSync( + config.authConfigFile, + JSON.stringify({ + username: 'admin', + password: newPassword, + }), + ); + return { + code: 100, + message: '已初始化密码,请前往auth.json查看并重新登录', + }; + } +} diff --git a/docker/front.conf b/docker/front.conf index e937611f..7a014e88 100644 --- a/docker/front.conf +++ b/docker/front.conf @@ -8,6 +8,9 @@ server { ssl_session_timeout 5m; location /api { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; +   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://api; } diff --git a/package.json b/package.json index b8564e9c..3db3f7db 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dotenv": "^8.2.0", "express": "^4.17.1", "express-jwt": "^6.0.0", + "got": "^11.8.2", "jsonwebtoken": "^8.5.1", "lodash": "^4.17.21", "nedb": "^1.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9cd07f26..28a5b194 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,7 @@ specifiers: '@types/react-dom': ^17.0.0 '@umijs/plugin-antd': ^0.9.1 '@umijs/test': ^3.3.9 + axios: ^0.21.1 body-parser: ^1.19.0 celebrate: ^13.0.3 codemirror: ^5.62.2 @@ -27,6 +28,7 @@ specifiers: dotenv: ^8.2.0 express: ^4.17.1 express-jwt: ^6.0.0 + got: ^11.8.2 jsonwebtoken: ^8.5.1 lint-staged: ^10.0.7 lodash: ^4.17.21 @@ -56,6 +58,7 @@ specifiers: yorkie: ^2.0.0 dependencies: + axios: 0.21.1 body-parser: 1.19.0 celebrate: 13.0.4 cors: 2.8.5 @@ -63,6 +66,7 @@ dependencies: dotenv: 8.6.0 express: 4.17.1 express-jwt: 6.0.0 + got: 11.8.2 jsonwebtoken: 8.5.1 lodash: 4.17.21 nedb: 1.8.0 @@ -935,6 +939,11 @@ packages: engines: {node: '>=6'} dev: true + /@sindresorhus/is/4.0.1: + resolution: {integrity: sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==} + engines: {node: '>=10'} + dev: false + /@sinonjs/commons/1.8.3: resolution: {integrity: sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==} dependencies: @@ -954,6 +963,13 @@ packages: defer-to-connect: 1.1.3 dev: true + /@szmarczak/http-timer/4.0.6: + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + dependencies: + defer-to-connect: 2.0.1 + dev: false + /@types/babel__core/7.1.14: resolution: {integrity: sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==} dependencies: @@ -990,6 +1006,15 @@ packages: '@types/node': 14.14.45 dev: true + /@types/cacheable-request/6.0.2: + resolution: {integrity: sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==} + dependencies: + '@types/http-cache-semantics': 4.0.1 + '@types/keyv': 3.1.2 + '@types/node': 14.17.11 + '@types/responselike': 1.0.0 + dev: false + /@types/connect/3.4.34: resolution: {integrity: sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==} dependencies: @@ -1058,6 +1083,10 @@ packages: resolution: {integrity: sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==} dev: true + /@types/http-cache-semantics/4.0.1: + resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} + dev: false + /@types/istanbul-lib-coverage/2.0.3: resolution: {integrity: sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==} dev: true @@ -1091,6 +1120,12 @@ packages: '@types/node': 14.14.45 dev: true + /@types/keyv/3.1.2: + resolution: {integrity: sha512-/FvAK2p4jQOaJ6CGDHJTqZcUtbZe820qIeTg7o0Shg7drB4JHeL+V/dhSaly7NXx6u8eSee+r7coT+yuJEvDLg==} + dependencies: + '@types/node': 14.17.11 + dev: false + /@types/lodash/4.14.170: resolution: {integrity: sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q==} dev: true @@ -1116,6 +1151,10 @@ packages: resolution: {integrity: sha512-DssMqTV9UnnoxDWu959sDLZzfvqCF0qDNRjaWeYSui9xkFe61kKo4l1TWNTQONpuXEm+gLMRvdlzvNHBamzmEw==} dev: true + /@types/node/14.17.11: + resolution: {integrity: sha512-n2OQ+0Bz6WEsUjrvcHD1xZ8K+Kgo4cn9/w94s1bJS690QMUWfJPW/m7CCb7gPkA1fcYwL2UpjXP/rq/Eo41m6w==} + dev: false + /@types/normalize-package-data/2.4.0: resolution: {integrity: sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==} dev: true @@ -1204,6 +1243,12 @@ packages: csstype: 3.0.8 dev: true + /@types/responselike/1.0.0: + resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} + dependencies: + '@types/node': 14.17.11 + dev: false + /@types/scheduler/0.16.1: resolution: {integrity: sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==} dev: true @@ -1963,6 +2008,14 @@ packages: resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==} dev: true + /axios/0.21.1: + resolution: {integrity: sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==} + dependencies: + follow-redirects: 1.14.2 + transitivePeerDependencies: + - debug + dev: false + /babel-core/7.0.0-bridge.0_@babel+core@7.12.10: resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: @@ -2355,6 +2408,11 @@ packages: unset-value: 1.0.0 dev: true + /cacheable-lookup/5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + dev: false + /cacheable-request/6.1.0: resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==} engines: {node: '>=8'} @@ -2368,6 +2426,19 @@ packages: responselike: 1.0.2 dev: true + /cacheable-request/7.0.2: + resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==} + engines: {node: '>=8'} + dependencies: + clone-response: 1.0.2 + get-stream: 5.2.0 + http-cache-semantics: 4.1.0 + keyv: 4.0.3 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.0 + dev: false + /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -2565,7 +2636,6 @@ packages: resolution: {integrity: sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=} dependencies: mimic-response: 1.0.1 - dev: true /co/4.6.0: resolution: {integrity: sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=} @@ -3073,6 +3143,13 @@ packages: mimic-response: 1.0.1 dev: true + /decompress-response/6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + /dedent/0.7.0: resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=} dev: true @@ -3100,6 +3177,11 @@ packages: resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==} dev: true + /defer-to-connect/2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + dev: false + /define-properties/1.1.3: resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==} engines: {node: '>= 0.4'} @@ -3300,7 +3382,6 @@ packages: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: once: 1.4.0 - dev: true /enhanced-resolve/5.8.2: resolution: {integrity: sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==} @@ -3757,6 +3838,16 @@ packages: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} dev: false + /follow-redirects/1.14.2: + resolution: {integrity: sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + /for-each/0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: @@ -3883,7 +3974,6 @@ packages: engines: {node: '>=8'} dependencies: pump: 3.0.0 - dev: true /get-value/2.0.6: resolution: {integrity: sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=} @@ -3930,6 +4020,23 @@ packages: engines: {node: '>=4'} dev: true + /got/11.8.2: + resolution: {integrity: sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==} + engines: {node: '>=10.19.0'} + dependencies: + '@sindresorhus/is': 4.0.1 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.2 + '@types/responselike': 1.0.0 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.2 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.0 + dev: false + /got/9.6.0: resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==} engines: {node: '>=8.6'} @@ -4110,7 +4217,6 @@ packages: /http-cache-semantics/4.1.0: resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==} - dev: true /http-errors/1.7.2: resolution: {integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==} @@ -4143,6 +4249,14 @@ packages: sshpk: 1.16.1 dev: true + /http2-wrapper/1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.0 + dev: false + /https-browserify/1.0.0: resolution: {integrity: sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=} dev: true @@ -5299,6 +5413,10 @@ packages: resolution: {integrity: sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=} dev: true + /json-buffer/3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: false + /json-parse-better-errors/1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} dev: true @@ -5387,6 +5505,12 @@ packages: json-buffer: 3.0.0 dev: true + /keyv/4.0.3: + resolution: {integrity: sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==} + dependencies: + json-buffer: 3.0.1 + dev: false + /kind-of/3.2.2: resolution: {integrity: sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=} engines: {node: '>=0.10.0'} @@ -5626,7 +5750,6 @@ packages: /lowercase-keys/2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} - dev: true /lru-cache/4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -5764,7 +5887,11 @@ packages: /mimic-response/1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} - dev: true + + /mimic-response/3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false /mini-create-react-context/0.4.1_prop-types@15.7.2+react@16.14.0: resolution: {integrity: sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==} @@ -6075,6 +6202,11 @@ packages: engines: {node: '>=8'} dev: true + /normalize-url/6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + dev: false + /normalize.css/7.0.0: resolution: {integrity: sha1-q/sd2CRwZ04DIrU86xqvQSk45L8=} dev: true @@ -6174,7 +6306,6 @@ packages: resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} dependencies: wrappy: 1.0.2 - dev: true /one-time/1.0.0: resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} @@ -6210,6 +6341,11 @@ packages: engines: {node: '>=6'} dev: true + /p-cancelable/2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + dev: false + /p-each-series/2.2.0: resolution: {integrity: sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==} engines: {node: '>=8'} @@ -6890,7 +7026,6 @@ packages: dependencies: end-of-stream: 1.4.4 once: 1.4.0 - dev: true /punycode/1.3.2: resolution: {integrity: sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=} @@ -6972,6 +7107,11 @@ packages: engines: {node: '>=0.4.x'} dev: true + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: false + /raf/3.4.1: resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} dependencies: @@ -8002,6 +8142,10 @@ packages: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} dev: true + /resolve-alpn/1.2.0: + resolution: {integrity: sha512-e4FNQs+9cINYMO5NMFc6kOUCdohjqFPSgMuwuZAOUWqrfWsen+Yjy5qZFkV5K7VO7tFSLKcUL97olkED7sCBHA==} + dev: false + /resolve-cwd/3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -8046,6 +8190,12 @@ packages: lowercase-keys: 1.0.1 dev: true + /responselike/2.0.0: + resolution: {integrity: sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==} + dependencies: + lowercase-keys: 2.0.0 + dev: false + /restore-cursor/3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -9639,7 +9789,6 @@ packages: /wrappy/1.0.2: resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} - dev: true /write-file-atomic/2.4.1: resolution: {integrity: sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==} diff --git a/shell/check.sh b/shell/check.sh index 1af99773..c0748d54 100644 --- a/shell/check.sh +++ b/shell/check.sh @@ -18,14 +18,20 @@ reset_env() { cp -f $dir_sample/package.json $dir_scripts/package.json npm_install_2 $dir_scripts echo -e "---> 脚本依赖安装完成\n" +} - echo -e "---> 4. 复制通知文件\n" +copy_dep() { + echo -e "---> 1. 复制通知文件\n" echo -e "---> 复制一份 $file_notify_py_sample 为 $file_notify_py\n" cp -fv $file_notify_py_sample $file_notify_py echo echo -e "---> 复制一份 $file_notify_js_sample 为 $file_notify_js\n" cp -fv $file_notify_js_sample $file_notify_js echo -e "---> 通知文件复制完成\n" + + echo -e "---> 2. 复制nginx配置文件\n" + cp -fv $nginx_conf /etc/nginx/conf.d/front.conf + echo -e "---> 配置文件复制完成\n" } reload_pm2() { @@ -57,6 +63,7 @@ check_nginx() { echo -e "=====> 检测nginx服务\n$nginxPid" if [[ $nginxPid ]]; then echo -e "\n=====> nginx服务正常\n" + nginx -s reload else echo -e "\n=====> nginx服务异常,重新启动nginx\n" nginx -c /etc/nginx/nginx.conf @@ -109,6 +116,7 @@ init_git() { main() { echo -e "=====> 开始检测" init_git + copy_dep check_ql check_nginx check_pm2 diff --git a/shell/share.sh b/shell/share.sh index 500cd4f3..fc1c23fb 100755 --- a/shell/share.sh +++ b/shell/share.sh @@ -32,6 +32,7 @@ file_notify_py_sample=$dir_sample/notify.py file_notify_py=$dir_scripts/notify.py file_notify_js=$dir_scripts/sendNotify.js task_error_log_path=$dir_log/task_error.log +nginx_conf=$dir_root/docker/front.conf ## 清单文件 list_crontab_user=$dir_config/crontab.list diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 2cc7904f..5c754e1f 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,5 +1,5 @@ import React, { Fragment, useEffect } from 'react'; -import { Button, Row, Input, Form, message } from 'antd'; +import { Button, Row, Input, Form, message, notification } from 'antd'; import config from '@/utils/config'; import { history, Link } from 'umi'; import styles from './index.less'; @@ -18,7 +18,21 @@ const Login = () => { }) .then((data) => { if (data.code === 200) { - localStorage.setItem(config.authKey, data.token); + const { token, lastip, lastaddr, lastlogon } = data.data; + localStorage.setItem(config.authKey, token); + notification.success({ + message: '登录成功!', + description: ( +
+
+ 最后登录时间:{new Date(lastlogon).toLocaleString() || '-'} +
+
最后登录地点:{lastaddr || '-'}
+
最后登录IP:{lastip || '-'}
+
+ ), + duration: 5, + }); history.push('/crontab'); } else if (data.code === 100) { message.warn(data.message);