200 lines
6.2 KiB
JavaScript
200 lines
6.2 KiB
JavaScript
const db = require('../../dbProxy');
|
||
const authorizationService = require('../../../services/authorization_service');
|
||
const deviceManager = require('../core/deviceManager');
|
||
|
||
/**
|
||
* 账户验证服务
|
||
* 统一处理账户启用状态、授权状态、在线状态的检查
|
||
*/
|
||
class AccountValidator {
|
||
/**
|
||
* 检查账户是否启用
|
||
* @param {string} sn_code - 设备序列号
|
||
* @returns {Promise<{enabled: boolean, reason?: string}>}
|
||
*/
|
||
async checkEnabled(sn_code) {
|
||
try {
|
||
const pla_account = db.getModel('pla_account');
|
||
const account = await pla_account.findOne({
|
||
where: { sn_code, is_delete: 0 },
|
||
attributes: ['is_enabled', 'name']
|
||
});
|
||
|
||
if (!account) {
|
||
return { enabled: false, reason: '账户不存在' };
|
||
}
|
||
|
||
if (!account.is_enabled) {
|
||
return { enabled: false, reason: '账户未启用' };
|
||
}
|
||
|
||
return { enabled: true };
|
||
} catch (error) {
|
||
console.error(`[账户验证] 检查启用状态失败 (${sn_code}):`, error);
|
||
return { enabled: false, reason: '检查失败' };
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查账户授权状态
|
||
* @param {string} sn_code - 设备序列号
|
||
* @returns {Promise<{authorized: boolean, days?: number, reason?: string}>}
|
||
*/
|
||
async checkAuthorization(sn_code) {
|
||
try {
|
||
const result = await authorizationService.checkAuthorization(sn_code);
|
||
|
||
if (!result.is_authorized) {
|
||
return {
|
||
authorized: false,
|
||
days: result.days_remaining || 0,
|
||
reason: result.message || '授权已过期'
|
||
};
|
||
}
|
||
|
||
return {
|
||
authorized: true,
|
||
days: result.days_remaining
|
||
};
|
||
} catch (error) {
|
||
console.error(`[账户验证] 检查授权状态失败 (${sn_code}):`, error);
|
||
return { authorized: false, reason: '授权检查失败' };
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查设备是否在线
|
||
* @param {string} sn_code - 设备序列号
|
||
* @param {number} offlineThreshold - 离线阈值(毫秒)
|
||
* @returns {{online: boolean, lastHeartbeat?: number, reason?: string}}
|
||
*/
|
||
checkOnline(sn_code, offlineThreshold = 3 * 60 * 1000) {
|
||
const device = deviceManager.devices.get(sn_code);
|
||
|
||
if (!device) {
|
||
return { online: false, reason: '设备从未发送心跳' };
|
||
}
|
||
|
||
const now = Date.now();
|
||
const lastHeartbeat = device.lastHeartbeat || 0;
|
||
const elapsed = now - lastHeartbeat;
|
||
|
||
if (elapsed > offlineThreshold) {
|
||
const minutes = Math.round(elapsed / (60 * 1000));
|
||
return {
|
||
online: false,
|
||
lastHeartbeat,
|
||
reason: `设备离线(最后心跳: ${minutes}分钟前)`
|
||
};
|
||
}
|
||
|
||
if (!device.isOnline) {
|
||
return { online: false, lastHeartbeat, reason: '设备标记为离线' };
|
||
}
|
||
|
||
return { online: true, lastHeartbeat };
|
||
}
|
||
|
||
/**
|
||
* 综合验证(启用 + 授权 + 在线)
|
||
* @param {string} sn_code - 设备序列号
|
||
* @param {object} options - 验证选项
|
||
* @param {boolean} options.checkEnabled - 是否检查启用状态(默认 true)
|
||
* @param {boolean} options.checkAuth - 是否检查授权(默认 true)
|
||
* @param {boolean} options.checkOnline - 是否检查在线(默认 true)
|
||
* @param {number} options.offlineThreshold - 离线阈值(默认 3分钟)
|
||
* @returns {Promise<{valid: boolean, reason?: string, details?: object}>}
|
||
*/
|
||
async validate(sn_code, options = {}) {
|
||
const {
|
||
checkEnabled = true,
|
||
checkAuth = true,
|
||
checkOnline = true,
|
||
offlineThreshold = 3 * 60 * 1000
|
||
} = options;
|
||
|
||
const details = {};
|
||
|
||
// 检查启用状态
|
||
if (checkEnabled) {
|
||
const enabledResult = await this.checkEnabled(sn_code);
|
||
details.enabled = enabledResult;
|
||
|
||
if (!enabledResult.enabled) {
|
||
return {
|
||
valid: false,
|
||
reason: enabledResult.reason,
|
||
details
|
||
};
|
||
}
|
||
}
|
||
|
||
// 检查授权状态
|
||
if (checkAuth) {
|
||
const authResult = await this.checkAuthorization(sn_code);
|
||
details.authorization = authResult;
|
||
|
||
if (!authResult.authorized) {
|
||
return {
|
||
valid: false,
|
||
reason: authResult.reason,
|
||
details
|
||
};
|
||
}
|
||
}
|
||
|
||
// 检查在线状态
|
||
if (checkOnline) {
|
||
const onlineResult = this.checkOnline(sn_code, offlineThreshold);
|
||
details.online = onlineResult;
|
||
|
||
if (!onlineResult.online) {
|
||
return {
|
||
valid: false,
|
||
reason: onlineResult.reason,
|
||
details
|
||
};
|
||
}
|
||
}
|
||
|
||
return { valid: true, details };
|
||
}
|
||
|
||
/**
|
||
* 批量验证多个账户
|
||
* @param {string[]} sn_codes - 设备序列号数组
|
||
* @param {object} options - 验证选项
|
||
* @returns {Promise<{valid: string[], invalid: Array<{sn_code: string, reason: string}>}>}
|
||
*/
|
||
async validateBatch(sn_codes, options = {}) {
|
||
const valid = [];
|
||
const invalid = [];
|
||
|
||
for (const sn_code of sn_codes) {
|
||
const result = await this.validate(sn_code, options);
|
||
|
||
if (result.valid) {
|
||
valid.push(sn_code);
|
||
} else {
|
||
invalid.push({ sn_code, reason: result.reason });
|
||
}
|
||
}
|
||
|
||
return { valid, invalid };
|
||
}
|
||
|
||
/**
|
||
* 检查账户是否已登录(通过心跳数据)
|
||
* @param {string} sn_code - 设备序列号
|
||
* @returns {boolean}
|
||
*/
|
||
checkLoggedIn(sn_code) {
|
||
const device = deviceManager.devices.get(sn_code);
|
||
return device?.isLoggedIn || false;
|
||
}
|
||
}
|
||
|
||
// 导出单例
|
||
const accountValidator = new AccountValidator();
|
||
module.exports = accountValidator;
|