Files
Docker-Proxy/hubcmdui/services/userService.js

176 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 用户服务模块
*/
const fs = require('fs').promises;
const path = require('path');
const bcrypt = require('bcrypt');
const logger = require('../logger');
const USERS_FILE = path.join(__dirname, '..', 'users.json');
// 获取所有用户
async function getUsers() {
try {
const data = await fs.readFile(USERS_FILE, 'utf8');
return JSON.parse(data);
} catch (error) {
if (error.code === 'ENOENT') {
logger.warn('Users file does not exist, creating default user');
const defaultUser = {
username: 'root',
password: bcrypt.hashSync('admin', 10),
createdAt: new Date().toISOString(),
loginCount: 0,
lastLogin: null
};
await saveUsers([defaultUser]);
return { users: [defaultUser] };
}
throw error;
}
}
// 保存用户
async function saveUsers(users) {
await fs.writeFile(USERS_FILE, JSON.stringify({ users }, null, 2), 'utf8');
}
// 更新用户登录信息
async function updateUserLoginInfo(username) {
try {
const { users } = await getUsers();
const user = users.find(u => u.username === username);
if (user) {
user.loginCount = (user.loginCount || 0) + 1;
user.lastLogin = new Date().toISOString();
await saveUsers(users);
}
} catch (error) {
logger.error('更新用户登录信息失败:', error);
}
}
// 获取用户统计信息
async function getUserStats(username) {
try {
const { users } = await getUsers();
const user = users.find(u => u.username === username);
if (!user) {
return { loginCount: '0', lastLogin: '未知', accountAge: '0' };
}
// 计算账户年龄(如果有创建日期)
let accountAge = '0';
if (user.createdAt) {
const createdDate = new Date(user.createdAt);
const currentDate = new Date();
const diffTime = Math.abs(currentDate - createdDate);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
accountAge = diffDays.toString();
}
// 格式化最后登录时间
let lastLogin = '未知';
if (user.lastLogin) {
const lastLoginDate = new Date(user.lastLogin);
const now = new Date();
const isToday = lastLoginDate.toDateString() === now.toDateString();
if (isToday) {
lastLogin = '今天 ' + lastLoginDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
} else {
lastLogin = lastLoginDate.toLocaleDateString() + ' ' + lastLoginDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
}
return {
username: user.username,
loginCount: (user.loginCount || 0).toString(),
lastLogin,
accountAge
};
} catch (error) {
logger.error('获取用户统计信息失败:', error);
return { loginCount: '0', lastLogin: '未知', accountAge: '0' };
}
}
// 创建新用户
async function createUser(username, password) {
try {
const { users } = await getUsers();
// 检查用户是否已存在
if (users.some(u => u.username === username)) {
throw new Error('用户名已存在');
}
const hashedPassword = bcrypt.hashSync(password, 10);
const newUser = {
username,
password: hashedPassword,
createdAt: new Date().toISOString(),
loginCount: 0,
lastLogin: null
};
users.push(newUser);
await saveUsers(users);
return { success: true, username };
} catch (error) {
logger.error('创建用户失败:', error);
throw error;
}
}
// 修改用户密码
async function changePassword(username, currentPassword, newPassword) {
try {
const { users } = await getUsers();
const user = users.find(u => u.username === username);
if (!user) {
throw new Error('用户不存在');
}
// 验证当前密码
const isMatch = await bcrypt.compare(currentPassword, user.password);
if (!isMatch) {
throw new Error('当前密码不正确');
}
// 验证新密码复杂度(虽然前端做了,后端再做一层保险)
if (!isPasswordComplex(newPassword)) {
throw new Error('新密码不符合复杂度要求');
}
// 更新密码
user.password = await bcrypt.hash(newPassword, 10);
await saveUsers(users);
logger.info(`用户 ${username} 密码已成功修改`);
} catch (error) {
logger.error('修改密码失败:', error);
throw error;
}
}
// 验证密码复杂度 (从 userCenter.js 复制过来并调整)
function isPasswordComplex(password) {
// 至少包含1个字母、1个数字和1个特殊字符长度在8-16位之间
const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[.,\-_+=()[\]{}|\\;:'"<>?/@$!%*#?&])[A-Za-z\d.,\-_+=()[\]{}|\\;:'"<>?/@$!%*#?&]{8,16}$/;
return passwordRegex.test(password);
}
module.exports = {
getUsers,
saveUsers,
updateUserLoginInfo,
getUserStats,
createUser,
changePassword
};