feat(auth): add local login, audit, API keys, and system admin UI

Gate netx Web/API/WebCRT with JWT and per-user API tokens, bootstrap an admin with forced password change, and expose users/audit/API-key management under a System section. MCP can reuse data/auth/mcp_token without extra env for local labs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
hansjone 2026-07-30 02:34:25 +00:00
parent 14f14d34bd
commit 6d4cd741ef
35 changed files with 2699 additions and 21 deletions

View file

@ -19,6 +19,7 @@ const en = {
openModule: "Open or switch to this module tab",
monitoring: "Monitoring",
operations: "Operations",
system: "System",
cards: {
umeSync: "UME Sync",
umeSyncDesc: "UME alarms, subscription & inventory",
@ -30,6 +31,12 @@ const en = {
webcrtDesc: "Interactive browser login to connected NEs (SSH/Telnet)",
topology: "Topology",
topologyDesc: "Drag NE topology maps; discover links via LLDP/CDP",
users: "Users",
usersDesc: "Admin: create, disable users and reset passwords",
audit: "Audit",
auditDesc: "View login and operation records",
apiKeys: "API Keys",
apiKeysDesc: "Issue MCP/script tokens per user with expiry",
},
},
layout: {
@ -39,6 +46,9 @@ const en = {
titleCollect: "Batch Collect",
titleWebcrt: "WebCRT",
titleTopology: "Topology",
titleUsers: "Users",
titleAudit: "Audit",
titleApiKeys: "API Keys",
navUme: "UME",
netxApi: "netx api",
oclawBridge: "oclaw WSS",
@ -47,6 +57,79 @@ const en = {
langZh: "中文",
langEn: "English",
},
auth: {
loginTitle: "Sign in to NetX",
loginHint: "Use a local account to access the ops platform",
username: "Username",
password: "Password",
login: "Sign in",
loggingIn: "Signing in…",
loginFailed: "Login failed",
logout: "Sign out",
usersTitle: "User management",
usersHint: "Only admins can create and manage local accounts.",
addUser: "Add user",
role: "Role",
roleAdmin: "Admin",
roleUser: "User",
status: "Status",
active: "Active",
disabled: "Disabled",
enable: "Enable",
disable: "Disable",
actions: "Actions",
newPassword: "New password",
resetPassword: "Reset password",
userCreated: "User created",
userUpdated: "User updated",
auditTitle: "Audit log",
auditHintAdmin: "View login and operation records for all users.",
auditHintUser: "View your own operation records.",
filterUsername: "Filter username",
filterAction: "Filter action",
colTime: "Time",
colUser: "User",
colAction: "Action",
colMethod: "Method",
colPath: "Path",
colStatus: "Status",
colIp: "IP",
apiKeysTitle: "API Key management",
apiKeysHint:
"Create long-lived tokens for MCP/scripts. The secret is shown only once. Admins can issue keys for other users.",
tokenName: "Name",
expiresIn: "Expiry",
expire7d: "7 days",
expire30d: "30 days",
expire90d: "90 days",
expire365d: "1 year",
expireNever: "Never",
tokenOwner: "Owner",
tokenOwnerSelf: "Myself ({{user}})",
createToken: "Create key",
tokenCreated: "API key created",
tokenRevoked: "Revoked",
tokenOnceHint: "Copy and store this secret now; it will not be shown again:",
copyToken: "Copy",
tokenCopied: "Copied",
tokenCopyFailed: "Copy failed",
expiresAt: "Expires",
lastUsed: "Last used",
tokenStatusActive: "Active",
tokenStatusExpired: "Expired",
tokenStatusRevoked: "Revoked",
revokeToken: "Revoke",
revokeConfirm: "Revoke this API key?",
forceChangeTitle: "Change initial password",
forceChangeHint: "Account {{user}} is still using the default password. You must change it before continuing.",
oldPassword: "Current password",
confirmPassword: "Confirm new password",
savePassword: "Save new password",
savingPassword: "Saving…",
passwordTooShort: "New password must be at least 6 characters",
passwordMismatch: "New passwords do not match",
passwordMustChange: "New password must differ from the default/old password",
},
collect: {
create: {
title: "New collection job",

View file

@ -19,6 +19,7 @@ const zh = {
openModule: "打开或切换到该模块页签",
monitoring: "监控",
operations: "运维",
system: "系统管理",
cards: {
umeSync: "UME同步",
umeSyncDesc: "UME 告警同步、订阅与清单",
@ -30,6 +31,12 @@ const zh = {
webcrtDesc: "浏览器内交互登录已连通网元(SSH/Telnet)",
topology: "拓扑管理",
topologyDesc: "拖拽编排网元拓扑,支持 LLDP/CDP 发现链路",
users: "用户管理",
usersDesc: "管理员添加、禁用用户并重置密码",
audit: "操作审计",
auditDesc: "查看登录与操作记录",
apiKeys: "API Key",
apiKeysDesc: "为用户生成 MCP/脚本用 Token,可设有效期",
},
},
layout: {
@ -39,6 +46,9 @@ const zh = {
titleCollect: "批量采集",
titleWebcrt: "WebCRT",
titleTopology: "拓扑管理",
titleUsers: "用户管理",
titleAudit: "操作审计",
titleApiKeys: "API Key",
navUme: "UME 对接",
netxApi: "netx api",
oclawBridge: "oclaw WSS",
@ -47,6 +57,78 @@ const zh = {
langZh: "中文",
langEn: "English",
},
auth: {
loginTitle: "登录 NetX",
loginHint: "使用本地账号访问运维平台",
username: "用户名",
password: "密码",
login: "登录",
loggingIn: "登录中…",
loginFailed: "登录失败",
logout: "退出",
usersTitle: "用户管理",
usersHint: "仅管理员可创建与管理本地账号。",
addUser: "添加用户",
role: "角色",
roleAdmin: "管理员",
roleUser: "普通用户",
status: "状态",
active: "启用",
disabled: "禁用",
enable: "启用",
disable: "禁用",
actions: "操作",
newPassword: "新密码",
resetPassword: "重置密码",
userCreated: "用户已创建",
userUpdated: "用户已更新",
auditTitle: "操作审计",
auditHintAdmin: "查看所有用户的登录与操作记录。",
auditHintUser: "查看你自己的操作记录。",
filterUsername: "用户名筛选",
filterAction: "动作筛选",
colTime: "时间",
colUser: "用户",
colAction: "动作",
colMethod: "方法",
colPath: "路径",
colStatus: "状态码",
colIp: "IP",
apiKeysTitle: "API Key 管理",
apiKeysHint: "生成长期 Token 供 MCP/脚本调用;明文仅创建时显示一次。管理员可为其他用户签发。",
tokenName: "名称",
expiresIn: "有效期",
expire7d: "7 天",
expire30d: "30 天",
expire90d: "90 天",
expire365d: "1 年",
expireNever: "永不过期",
tokenOwner: "所属用户",
tokenOwnerSelf: "自己({{user}})",
createToken: "生成 Key",
tokenCreated: "API Key 已生成",
tokenRevoked: "已吊销",
tokenOnceHint: "请立即复制保存,关闭后无法再次查看明文:",
copyToken: "复制",
tokenCopied: "已复制到剪贴板",
tokenCopyFailed: "复制失败",
expiresAt: "到期时间",
lastUsed: "最近使用",
tokenStatusActive: "有效",
tokenStatusExpired: "已过期",
tokenStatusRevoked: "已吊销",
revokeToken: "吊销",
revokeConfirm: "确定吊销该 API Key?",
forceChangeTitle: "请修改初始密码",
forceChangeHint: "账号 {{user}} 仍在使用默认密码,登录前必须先修改。",
oldPassword: "当前密码",
confirmPassword: "确认新密码",
savePassword: "保存新密码",
savingPassword: "保存中…",
passwordTooShort: "新密码至少 6 位",
passwordMismatch: "两次输入的新密码不一致",
passwordMustChange: "新密码不能与默认/旧密码相同",
},
collect: {
create: {
title: "新建采集任务",