登录增加最后登录时间地点,登录失败增加重试间隔

This commit is contained in:
hanhh
2021-08-22 01:22:23 +08:00
parent 61e41269ba
commit 54bb13aad0
9 changed files with 365 additions and 69 deletions
+24 -57
View File
@@ -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);
+50
View File
@@ -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 };
}
}
+103
View File
@@ -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<any> {
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查看并重新登录',
};
}
}