'use strict'; /** * 登录日志-数据模型 * * @author lanjianrong * @date 2020/8/31 * @version */ const UAParser = require('ua-parser-js'); module.exports = app => { class LoginLogging extends app.BaseService { constructor(ctx) { super(ctx); this.tableName = 'login_logging'; } /** * 创建记录 * @param {Object} payload - 载荷 */ async createLog(payload) { const transaction = await this.db.beginTransaction(); try { transaction.insert(this.tableName, payload); await transaction.commit(); } catch (error) { await transaction.rollback(); throw error; } } /** * 创建登录日志 * @return {Boolean} 日志是否创建成功 */ async addLoginLog() { const { ctx } = this; const ip = ctx.header['x-real-ip'] ? ctx.header['x-real-ip'] : ''; const ipInfo = await this.getIpInfoFromApi(ip); const parser = new UAParser(ctx.header['user-agent']); const osInfo = parser.getOS(); const cpuInfo = parser.getCPU(); const browserInfo = parser.getBrowser(); const payload = { os: `${osInfo.name} ${osInfo.version} ${cpuInfo.architecture}`, browser: `${browserInfo.name} ${browserInfo.version}`, ip, address: ipInfo, uid: ctx.session.sessionUser.accountId, pid: ctx.session.sessionProject.id, }; return await this.createLog(payload); } /** * 根据ip请求获取详细地址 * @param {String} a_ip - ip地址 * @return {String} 详细地址 */ async getIpInfoFromApi(a_ip = '') { if (!a_ip) return ''; if (a_ip === '127.0.0.1') return '服务器本机访问'; const { ip = '', region = '', city = '', isp = '' } = await this.sendRequest(a_ip); let address = ''; region && (address += region + '省'); city && (address += city + '市 '); isp && (address += isp + ' '); ip && (address += `(${ip})`); return address; } /** * 发送请求获取详细地址 * @param {String} ip - ip地址 * @param {Number} max - 最大重试次数 * @return {Object} the result of request * @private */ async sendRequest(ip, max = 3) { return new Promise(resolve => { const start = () => { if (max <= 0) { resolve(); // 已达到最大重试次数,返回空的执行承若 } max--; this.ctx.curl(`https://api01.aliyun.venuscn.com/ip?ip=${ip}`, { dateType: 'json', encoding: 'utf8', timeout: 2000, headers: { Authorization: 'APPCODE 85c64bffe70445c4af9df7ae31c7bfcc', }, }).then(({ status, data }) => { if (status === 200) { const result = JSON.parse(data.toString()).data; if (!result.ip) { start(); } else { max++; resolve(result); } } else { max--; start(); } }).catch(() => { start(); }); }; start(); }); } /** * 获取登录日志 * @param {Number} pid - 项目id * @param {Number} uid - 用户id * @return {Promise} 日志数组 */ async getLoginLogs(pid, uid) { return this.db.select(this.tableName, { where: { pid, uid }, orders: [['create_time', 'desc']], columns: ['browser', 'create_time', 'ip', 'os', 'address'], limit: 10, offset: 0, }); } } return LoginLogging; };