fix: 统一管理员密码管理机制,以init.json为唯一数据源

- app.js: 每次启动强制从init.json加载管理员凭据到Redis,确保数据一致性
- web.js: 修改密码时先更新init.json,成功后再更新Redis缓存
- cli/index.js: CLI创建管理员时同时更新init.json和Redis
- setup.js: 优化提示信息,明确重置密码需要重启服务
- admin.js: 修复Claude账户专属绑定功能的验证逻辑

解决了之前存在的双重存储同步问题,现在init.json是唯一真实数据源。

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-17 20:57:31 +08:00
parent ee9bd4aea4
commit 11873ed78b
6 changed files with 188 additions and 74 deletions

View File

@@ -7,6 +7,8 @@ const ora = require('ora');
const Table = require('table').table;
const bcrypt = require('bcryptjs');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const config = require('../config/config');
const redis = require('../src/models/redis');
@@ -104,6 +106,27 @@ program
async function createInitialAdmin() {
console.log(styles.title('\n🔐 创建初始管理员账户\n'));
// 检查是否已存在 init.json
const initFilePath = path.join(__dirname, '..', 'data', 'init.json');
if (fs.existsSync(initFilePath)) {
const existingData = JSON.parse(fs.readFileSync(initFilePath, 'utf8'));
console.log(styles.warning('⚠️ 检测到已存在管理员账户!'));
console.log(` 用户名: ${existingData.adminUsername}`);
console.log(` 创建时间: ${new Date(existingData.initializedAt).toLocaleString()}`);
const { overwrite } = await inquirer.prompt([{
type: 'confirm',
name: 'overwrite',
message: '是否覆盖现有管理员账户?',
default: false
}]);
if (!overwrite) {
console.log(styles.info(' 已取消创建'));
return;
}
}
const adminData = await inquirer.prompt([
{
type: 'input',
@@ -129,20 +152,43 @@ async function createInitialAdmin() {
const spinner = ora('正在创建管理员账户...').start();
try {
// 1. 先更新 init.json唯一真实数据源
const initData = {
initializedAt: new Date().toISOString(),
adminUsername: adminData.username,
adminPassword: adminData.password, // 保存明文密码
version: '1.0.0',
updatedAt: new Date().toISOString()
};
// 确保 data 目录存在
const dataDir = path.join(__dirname, '..', 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
// 写入文件
fs.writeFileSync(initFilePath, JSON.stringify(initData, null, 2));
// 2. 再更新 Redis 缓存
const passwordHash = await bcrypt.hash(adminData.password, 12);
const credentials = {
username: adminData.username,
passwordHash,
createdAt: new Date().toISOString(),
id: crypto.randomBytes(16).toString('hex')
lastLogin: null,
updatedAt: new Date().toISOString()
};
await redis.setSession('admin_credentials', credentials, 0); // 永不过期
spinner.succeed('管理员账户创建成功');
console.log(`${styles.success('✅')} 用户名: ${adminData.username}`);
console.log(`${styles.success('✅')} 密码: ${adminData.password}`);
console.log(`${styles.info('')} 请妥善保管登录凭据`);
console.log(`${styles.info('')} 凭据已保存到: ${initFilePath}`);
console.log(`${styles.warning('⚠️')} 如果服务正在运行,请重启服务以加载新凭据`);
} catch (error) {
spinner.fail('创建管理员账户失败');