feat: MCP 端点鉴权改用后台 Token 管理,废弃 mcp_kv 配置
build-and-deploy / build-and-deploy (push) Successful in 42s
build-and-deploy / build-and-deploy (push) Successful in 42s
- tokenService 支持 mcpEnabled 标记,新增 getMcpTokenValues 与迁移逻辑 - /mcp 鉴权改为校验 Token 表中标记为 MCP 访问的生效令牌 - 启动时自动把旧 mcp_token 配置迁成一条 MCP Token,保证旧客户端不中断 - admin 页面 Token 表新增 MCP 访问列与生成/编辑开关 - 新增 tokenService 测试(58 项全部通过)
This commit is contained in:
+16
-3
@@ -117,7 +117,7 @@
|
||||
<table class="data-table" id="token-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th><th>关联项目</th><th>权限</th><th>Token</th>
|
||||
<th>名称</th><th>关联项目</th><th>权限</th><th>MCP 访问</th><th>Token</th>
|
||||
<th>状态</th><th>过期时间</th><th>创建时间</th><th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -229,6 +229,12 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label" style="display:flex;align-items:center;gap:8px;cursor:pointer">
|
||||
<input type="checkbox" id="input-token-mcp" style="width:16px;height:16px">
|
||||
<span>作为 MCP 访问令牌(用于 /mcp 端点鉴权)</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="hint">生成后 Token 明文仅展示一次,请及时复制并妥善保管。</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -486,7 +492,7 @@
|
||||
function renderTokens(tokens) {
|
||||
var tbody = document.getElementById("token-tbody");
|
||||
if (!tokens.length) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" style="text-align:center;color:#999;padding:30px">暂无 Token</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="9" style="text-align:center;color:#999;padding:30px">暂无 Token</td></tr>';
|
||||
return;
|
||||
}
|
||||
tbody.innerHTML = tokens.map(function (t) {
|
||||
@@ -499,6 +505,9 @@
|
||||
"<td>" + esc(t.name) + "</td>" +
|
||||
"<td>" + esc(t.projectId === "all" ? "全部项目" : t.projectId) + "</td>" +
|
||||
'<td><span class="dim-chip">' + (t.permission === "readwrite" ? "读写" : "只读") + "</span></td>" +
|
||||
'<td>' + (t.mcpEnabled
|
||||
? '<span class="dim-chip" style="color:#0a7a3c;border-color:#0a7a3c">MCP</span>'
|
||||
: '<span style="color:#aaa">—</span>') + "</td>" +
|
||||
'<td><div class="token-reveal">' +
|
||||
'<span class="token-value token-mask" data-id="' + t.id + '">' + masked + "</span>" +
|
||||
'<button class="token-btn" onclick="toggleTokenVis(this)">显示</button>' +
|
||||
@@ -508,7 +517,7 @@
|
||||
"<td>" + fmtDate(t.expiresAt) + "</td>" +
|
||||
"<td>" + fmtDate(t.createdAt) + "</td>" +
|
||||
'<td style="white-space:nowrap">' +
|
||||
'<button class="row-btn" onclick=\'editToken(' + JSON.stringify({ id: t.id, name: t.name, projectId: t.projectId, permission: t.permission }).replace(/'/g, "'") + ")'>编辑</button> " +
|
||||
'<button class="row-btn" onclick=\'editToken(' + JSON.stringify({ id: t.id, name: t.name, projectId: t.projectId, permission: t.permission, mcpEnabled: !!t.mcpEnabled }).replace(/'/g, "'") + ")'>编辑</button> " +
|
||||
(t.enabled
|
||||
? '<button class="row-btn danger" onclick="revokeToken(\'' + t.id + "')\">吊销</button>"
|
||||
: "") +
|
||||
@@ -559,6 +568,7 @@
|
||||
document.getElementById("input-token-project").value = "all";
|
||||
document.getElementById("input-token-permission").value = "readonly";
|
||||
document.getElementById("input-token-expiry").value = "90";
|
||||
document.getElementById("input-token-mcp").checked = false;
|
||||
document.getElementById("btn-save-token").textContent = "生成";
|
||||
loadProjectsForSelect();
|
||||
openModal("modal-token");
|
||||
@@ -570,6 +580,7 @@
|
||||
document.getElementById("input-token-name").value = t.name;
|
||||
document.getElementById("input-token-project").value = t.projectId;
|
||||
document.getElementById("input-token-permission").value = t.permission;
|
||||
document.getElementById("input-token-mcp").checked = !!(t.mcpEnabled);
|
||||
document.getElementById("btn-save-token").textContent = "保存";
|
||||
loadProjectsForSelect();
|
||||
openModal("modal-token");
|
||||
@@ -585,6 +596,7 @@
|
||||
name: name,
|
||||
projectId: document.getElementById("input-token-project").value,
|
||||
permission: document.getElementById("input-token-permission").value,
|
||||
mcpEnabled: document.getElementById("input-token-mcp").checked,
|
||||
});
|
||||
closeModal("modal-token");
|
||||
toast("Token 已更新", "success");
|
||||
@@ -594,6 +606,7 @@
|
||||
name: name,
|
||||
projectId: document.getElementById("input-token-project").value,
|
||||
permission: document.getElementById("input-token-permission").value,
|
||||
mcpEnabled: document.getElementById("input-token-mcp").checked,
|
||||
expiresInDays: parseInt(document.getElementById("input-token-expiry").value) || 0,
|
||||
});
|
||||
closeModal("modal-token");
|
||||
|
||||
Reference in New Issue
Block a user