feat(core): mgmt 接入 core 进程管理 + 管理员认证

- gateway 新增 POST /admin/verify 验签接口,供内部服务校验管理员 Token
- core 的 /list /exec /kill 接入管理员认证(调用 gateway 验签,fail-closed)
- gateway 代理 opened 白名单加入 core:5200
- mgmt 管理页显示当前用户与角色,进程页接入 core 进程管理接口
This commit is contained in:
qing committed 2026-08-04 20:00:24 +08:00
1 parent c8812dd27c
commit 34cd295005
6 files changed
+381 -9

No files matched your search

+111 -7
View File
@@ -33,7 +33,7 @@
</div>
<div class="input">
<div class="prompt">输入模块名:</div>
<div class="prompt">输入命令:</div>
<input id="input-area" class="input-area" type="text">
</div>
<button class="create-btn" onclick="createProcess()">创建</button>
@@ -41,25 +41,124 @@
</div>
<script>
// core 进程管理接口经 gateway 代理(Target-Url 指向 core:5200)
const CORE_TARGET = "http://127.0.0.1:5200";
function handleUnauthorized(res) {
if (res.status === 401) {
alert("未授权或管理员 Token 已失效,请重新登录");
setTimeout(() => { window.location.href = "../index.html"; }, 800);
return true;
}
return false;
}
async function api(path, body) {
const res = await fetch(path, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Target-Url': CORE_TARGET
},
body: body ? JSON.stringify(body) : '{}'
});
if (handleUnauthorized(res)) return null;
const text = await res.text();
let result;
try {
result = JSON.parse(text);
} catch (e) {
console.error('接口返回非 JSON:', text);
throw new Error('服务器响应格式异常 (HTTP ' + res.status + ')');
}
if (!res.ok || !result.success) {
throw new Error(result.message || '请求失败 (HTTP ' + res.status + ')');
}
return result;
}
// 列表接口返回的 data,可能是数组,也可能是 ptree 序列化后的
// {"": {...}, "": {...}} 对象(boost property_tree 对数组的表示)
function toProcessArray(data) {
if (Array.isArray(data)) return data;
if (data && typeof data === "object") {
return Object.values(data);
}
return [];
}
async function loadProcesses() {
const tbody = document.getElementById("tBody");
const progress = document.getElementById("inProgressText");
tbody.innerHTML = "";
progress.innerText = "加载中...";
try {
const result = await api('/list');
const list = toProcessArray(result.data);
tbody.innerHTML = "";
for (let i = 0; i < list.length; i++) {
const p = list[i];
const tr = document.createElement("tr");
const pid = p.pid;
const status = p.status === true ? "运行中" : (p.status === false ? "已停止" : (p.status || "未知"));
tr.innerHTML = `
<td>${pid}</td>
<td>${status}</td>
<td>${p.command || p.target || "-"}</td>
<td><button class="stopBtn" onclick="stopBtn(${pid})">停止</button></td>
`;
tbody.appendChild(tr);
}
progress.innerText = "";
} catch (err) {
progress.innerText = "";
tbody.innerHTML = "";
alert(err.message || '加载进程列表失败');
}
}
function newBtn() {
const modal = document.getElementById("modal-con")
modal.style.display = "flex"
}
function createProcess() {
const moduleName = document.getElementById("input-area").value
alert("注意:这是静态页面 - 创建进程需要后端 API 支持,请通过 mgmt Flask 后端访问");
async function createProcess() {
const moduleName = document.getElementById("input-area").value.trim()
if (!moduleName) {
alert("请输入要执行的命令");
return;
}
const progress = document.getElementById("inProgressText");
progress.innerText = "启动中...";
try {
await api('/exec', { command: moduleName });
alert("启动成功");
closeModal();
await loadProcesses();
} catch (err) {
progress.innerText = "";
alert(err.message || '启动失败');
}
}
function flushBtn() {
window.location.reload()
loadProcesses();
}
function stopBtn(pid) {
async function stopBtn(pid) {
if (!confirm("确认停止该服务?")) {
return
}
alert("注意:这是静态页面 - 停止进程需要后端 API 支持,请通过 mgmt Flask 后端访问");
const progress = document.getElementById("inProgressText");
progress.innerText = "停止中...";
try {
await api('/kill', { pid: pid });
alert("已停止");
await loadProcesses();
} catch (err) {
progress.innerText = "";
alert(err.message || '停止失败');
}
}
function closeModal() {
@@ -69,6 +168,11 @@
input.value = ""
modal.style.display = "none"
}
// 页面加载时自动拉取进程列表
window.onload = () => {
loadProcesses();
};
</script>
</body>
+32
View File
@@ -9,7 +9,39 @@
<link rel="stylesheet" href="mgmt.css">
<script>
async function loadUserInfo() {
try {
const res = await fetch('/whoami', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: '{}'
});
const data = await res.json();
if (data.login && data.user) {
document.getElementById("current-user").innerText = "当前用户: " + data.user;
document.getElementById("current-role").innerText = data.is_admin ? "当前角色: 管理员" : "当前角色: 普通用户";
if (!data.is_admin) {
alert("需要管理员权限才能访问此页面");
}
} else {
document.getElementById("current-user").innerText = "当前用户: 未登录";
document.getElementById("current-role").innerText = "当前角色: 未知";
setTimeout(() => {
window.location = "index.html";
}, 1000);
}
} catch (err) {
console.error('获取用户信息失败:', err);
document.getElementById("current-user").innerText = "当前用户: 未知";
document.getElementById("current-role").innerText = "当前角色: 未知";
}
}
window.onload = () => {
loadUserInfo();
const featureList = [
{
name: "进程",