添加改密接口
This commit is contained in:
@@ -302,6 +302,7 @@
|
|||||||
<div class="modal-tabs">
|
<div class="modal-tabs">
|
||||||
<button class="modal-tab active" data-tab="prom">数据源管理</button>
|
<button class="modal-tab active" data-tab="prom">数据源管理</button>
|
||||||
<button class="modal-tab" data-tab="site">大屏设置</button>
|
<button class="modal-tab" data-tab="site">大屏设置</button>
|
||||||
|
<button class="modal-tab" data-tab="auth">账号安全</button>
|
||||||
</div>
|
</div>
|
||||||
<button class="modal-close" id="modalClose">×</button>
|
<button class="modal-close" id="modalClose">×</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -374,6 +375,29 @@
|
|||||||
<div class="form-message" id="siteSettingsMessage"></div>
|
<div class="form-message" id="siteSettingsMessage"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Account Security Tab -->
|
||||||
|
<div class="tab-content" id="tab-auth">
|
||||||
|
<div class="security-settings-form">
|
||||||
|
<h3>修改登录密码</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="oldPassword">当前密码</label>
|
||||||
|
<input type="password" id="oldPassword" placeholder="请输入当前旧密码">
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="margin-top: 15px;">
|
||||||
|
<label for="newPassword">新密码</label>
|
||||||
|
<input type="password" id="newPassword" placeholder="请输入要设置的新密码">
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="margin-top: 15px;">
|
||||||
|
<label for="confirmNewPassword">确认新密码</label>
|
||||||
|
<input type="password" id="confirmNewPassword" placeholder="请再次确认新密码">
|
||||||
|
</div>
|
||||||
|
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
||||||
|
<button class="btn btn-add" id="btnChangePassword">提交修改</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-message" id="changePasswordMessage"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -70,9 +70,14 @@
|
|||||||
detailMemTotal: document.getElementById('detailMemTotal'),
|
detailMemTotal: document.getElementById('detailMemTotal'),
|
||||||
detailUptime: document.getElementById('detailUptime'),
|
detailUptime: document.getElementById('detailUptime'),
|
||||||
detailContainer: document.getElementById('detailContainer'),
|
detailContainer: document.getElementById('detailContainer'),
|
||||||
sourceFilter: document.getElementById('sourceFilter'),
|
|
||||||
pageSizeSelect: document.getElementById('pageSizeSelect'),
|
pageSizeSelect: document.getElementById('pageSizeSelect'),
|
||||||
paginationControls: document.getElementById('paginationControls')
|
paginationControls: document.getElementById('paginationControls'),
|
||||||
|
// Auth security
|
||||||
|
oldPasswordInput: document.getElementById('oldPassword'),
|
||||||
|
newPasswordInput: document.getElementById('newPassword'),
|
||||||
|
confirmNewPasswordInput: document.getElementById('confirmNewPassword'),
|
||||||
|
btnChangePassword: document.getElementById('btnChangePassword'),
|
||||||
|
changePasswordMessage: document.getElementById('changePasswordMessage')
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---- State ----
|
// ---- State ----
|
||||||
@@ -124,6 +129,11 @@
|
|||||||
|
|
||||||
// Site settings
|
// Site settings
|
||||||
dom.btnSaveSiteSettings.addEventListener('click', saveSiteSettings);
|
dom.btnSaveSiteSettings.addEventListener('click', saveSiteSettings);
|
||||||
|
|
||||||
|
// Auth password change
|
||||||
|
if (dom.btnChangePassword) {
|
||||||
|
dom.btnChangePassword.addEventListener('click', saveChangePassword);
|
||||||
|
}
|
||||||
|
|
||||||
// Keyboard shortcut
|
// Keyboard shortcut
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
@@ -721,6 +731,12 @@
|
|||||||
dom.settingsModal.classList.remove('active');
|
dom.settingsModal.classList.remove('active');
|
||||||
hideMessage();
|
hideMessage();
|
||||||
hideSiteMessage();
|
hideSiteMessage();
|
||||||
|
hideChangePasswordMessage();
|
||||||
|
|
||||||
|
// Reset password fields
|
||||||
|
if (dom.oldPasswordInput) dom.oldPasswordInput.value = '';
|
||||||
|
if (dom.newPasswordInput) dom.newPasswordInput.value = '';
|
||||||
|
if (dom.confirmNewPasswordInput) dom.confirmNewPasswordInput.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Tab Switching ----
|
// ---- Tab Switching ----
|
||||||
@@ -849,6 +865,76 @@
|
|||||||
dom.siteSettingsMessage.className = 'form-message';
|
dom.siteSettingsMessage.className = 'form-message';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveChangePassword() {
|
||||||
|
if (!user) {
|
||||||
|
showChangePasswordMessage('请先登录后操作', 'error');
|
||||||
|
openLoginModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldPassword = dom.oldPasswordInput.value;
|
||||||
|
const newPassword = dom.newPasswordInput.value;
|
||||||
|
const confirmNewPassword = dom.confirmNewPasswordInput.value;
|
||||||
|
|
||||||
|
if (!oldPassword || !newPassword || !confirmNewPassword) {
|
||||||
|
showChangePasswordMessage('请填写所有密码字段', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPassword !== confirmNewPassword) {
|
||||||
|
showChangePasswordMessage('两次输入的新密码不一致', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPassword.length < 6) {
|
||||||
|
showChangePasswordMessage('新密码长度至少为 6 位', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.btnChangePassword.disabled = true;
|
||||||
|
dom.btnChangePassword.textContent = '提交中...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/auth/change-password', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
oldPassword,
|
||||||
|
newPassword
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
showChangePasswordMessage('密码修改成功', 'success');
|
||||||
|
dom.oldPasswordInput.value = '';
|
||||||
|
dom.newPasswordInput.value = '';
|
||||||
|
dom.confirmNewPasswordInput.value = '';
|
||||||
|
} else {
|
||||||
|
showChangePasswordMessage(data.error || '修改失败', 'error');
|
||||||
|
if (response.status === 401 && data.error === 'Auth required') openLoginModal();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
showChangePasswordMessage(`请求失败: ${err.message}`, 'error');
|
||||||
|
} finally {
|
||||||
|
dom.btnChangePassword.disabled = false;
|
||||||
|
dom.btnChangePassword.textContent = '提交修改';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showChangePasswordMessage(text, type) {
|
||||||
|
dom.changePasswordMessage.textContent = text;
|
||||||
|
dom.changePasswordMessage.className = `form-message ${type}`;
|
||||||
|
setTimeout(hideChangePasswordMessage, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideChangePasswordMessage() {
|
||||||
|
dom.changePasswordMessage.className = 'form-message';
|
||||||
|
}
|
||||||
|
|
||||||
function updateSourceFilterOptions(sources) {
|
function updateSourceFilterOptions(sources) {
|
||||||
if (!dom.sourceFilter) return;
|
if (!dom.sourceFilter) return;
|
||||||
const current = dom.sourceFilter.value;
|
const current = dom.sourceFilter.value;
|
||||||
|
|||||||
@@ -80,6 +80,34 @@ app.post('/api/auth/logout', (req, res) => {
|
|||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post('/api/auth/change-password', requireAuth, async (req, res) => {
|
||||||
|
const { oldPassword, newPassword } = req.body;
|
||||||
|
if (!oldPassword || !newPassword) {
|
||||||
|
return res.status(400).json({ error: '需要输入旧密码和新密码' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [rows] = await db.query('SELECT * FROM users WHERE id = ?', [req.user.id]);
|
||||||
|
if (rows.length === 0) return res.status(404).json({ error: '用户不存在' });
|
||||||
|
|
||||||
|
const user = rows[0];
|
||||||
|
const oldHash = crypto.pbkdf2Sync(oldPassword, user.salt, 1000, 64, 'sha512').toString('hex');
|
||||||
|
|
||||||
|
if (oldHash !== user.password) {
|
||||||
|
return res.status(401).json({ error: '旧密码输入错误' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const newSalt = crypto.randomBytes(16).toString('hex');
|
||||||
|
const newHash = crypto.pbkdf2Sync(newPassword, newSalt, 1000, 64, 'sha512').toString('hex');
|
||||||
|
|
||||||
|
await db.query('UPDATE users SET password = ?, salt = ? WHERE id = ?', [newHash, newSalt, user.id]);
|
||||||
|
res.json({ success: true, message: '密码修改成功' });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Password update error:', err);
|
||||||
|
res.status(500).json({ error: '服务器错误,修改失败' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/api/auth/status', (req, res) => {
|
app.get('/api/auth/status', (req, res) => {
|
||||||
const sessionId = getCookie(req, 'session_id');
|
const sessionId = getCookie(req, 'session_id');
|
||||||
if (sessionId && sessions.has(sessionId)) {
|
if (sessionId && sessions.has(sessionId)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user