mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 添加管理员账户信息修改功能
- 新增右上角用户菜单,包含修改账户信息和退出登录选项 - 实现修改用户名和密码功能,支持独立修改或同时修改 - 添加密码强度验证(最少8位)和确认密码验证 - 修改后自动退出登录,确保安全性 - 同步更新Redis和data/init.json文件,保持数据一致性 - 优化用户体验,提供实时反馈和错误提示 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,112 @@ router.post('/auth/logout', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 🔑 修改账户信息
|
||||
router.post('/auth/change-password', async (req, res) => {
|
||||
try {
|
||||
const token = req.headers['authorization']?.replace('Bearer ', '') || req.cookies?.adminToken;
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
error: 'No token provided',
|
||||
message: 'Authentication required'
|
||||
});
|
||||
}
|
||||
|
||||
const { newUsername, currentPassword, newPassword } = req.body;
|
||||
|
||||
if (!currentPassword || !newPassword) {
|
||||
return res.status(400).json({
|
||||
error: 'Missing required fields',
|
||||
message: 'Current password and new password are required'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证新密码长度
|
||||
if (newPassword.length < 8) {
|
||||
return res.status(400).json({
|
||||
error: 'Password too short',
|
||||
message: 'New password must be at least 8 characters long'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前会话
|
||||
const sessionData = await redis.getSession(token);
|
||||
if (!sessionData) {
|
||||
return res.status(401).json({
|
||||
error: 'Invalid token',
|
||||
message: 'Session expired or invalid'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前管理员信息
|
||||
const adminData = await redis.getSession('admin_credentials');
|
||||
if (!adminData) {
|
||||
return res.status(500).json({
|
||||
error: 'Admin data not found',
|
||||
message: 'Administrator credentials not found'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证当前密码
|
||||
const isValidPassword = await bcrypt.compare(currentPassword, adminData.passwordHash);
|
||||
if (!isValidPassword) {
|
||||
logger.security(`🔒 Invalid current password attempt for user: ${sessionData.username}`);
|
||||
return res.status(401).json({
|
||||
error: 'Invalid current password',
|
||||
message: 'Current password is incorrect'
|
||||
});
|
||||
}
|
||||
|
||||
// 准备更新的数据
|
||||
const saltRounds = 10;
|
||||
const newPasswordHash = await bcrypt.hash(newPassword, saltRounds);
|
||||
|
||||
const updatedAdminData = {
|
||||
...adminData,
|
||||
passwordHash: newPasswordHash,
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
// 如果提供了新用户名,则更新用户名
|
||||
if (newUsername && newUsername.trim() && newUsername !== adminData.username) {
|
||||
updatedAdminData.username = newUsername.trim();
|
||||
}
|
||||
|
||||
// 更新Redis中的管理员凭据
|
||||
await redis.setSession('admin_credentials', updatedAdminData);
|
||||
|
||||
// 更新data/init.json文件
|
||||
const initFilePath = path.join(__dirname, '../../data/init.json');
|
||||
if (fs.existsSync(initFilePath)) {
|
||||
const initData = JSON.parse(fs.readFileSync(initFilePath, 'utf8'));
|
||||
initData.adminUsername = updatedAdminData.username;
|
||||
initData.adminPassword = newPassword; // 保存明文密码到init.json
|
||||
initData.updatedAt = new Date().toISOString();
|
||||
|
||||
fs.writeFileSync(initFilePath, JSON.stringify(initData, null, 2));
|
||||
}
|
||||
|
||||
// 清除当前会话(强制用户重新登录)
|
||||
await redis.deleteSession(token);
|
||||
|
||||
logger.success(`🔐 Admin password changed successfully for user: ${updatedAdminData.username}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Password changed successfully. Please login again.',
|
||||
newUsername: updatedAdminData.username
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('❌ Change password error:', error);
|
||||
res.status(500).json({
|
||||
error: 'Change password failed',
|
||||
message: 'Internal server error'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 🔄 刷新token
|
||||
router.post('/auth/refresh', async (req, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user