InfraGuard

登录与认证

控制台会话登录如何工作、会话如何在每次请求时重新同步,以及外部接入 API 如何认证。

概述 — 这套机制做什么

InfraGuard 有 两个认证平面:

  1. Web 控制台 = 会话登录。 运维人员用 login_id + password 登录,AuthController 会创建一个自定义会话。此后每个控制台页面都会经过 infr.auth 中间件(InfrAuth),它在校验会话的同时 在每次请求时都从数据库重新读取用户的级别、姓名和语言,以保持会话副本同步。
  2. 外部接入 API = 无状态的 API 密钥 Bearer 认证。 当外部应用上报事件、备份结果或安全扫描时,它通过 infr.apikey 中间件用 API 密钥令牌(Authorization: Bearer … 或 X-Infr-Api-Key)认证,而不是会话。没有会话,也没有 CSRF。

主要特性:

何时使用

页面构成

登录页面(/login)是一张简单的卡片。

元素 说明
品牌 · 标语 Infra**Guard** 徽标 +「融合基础设施运维 · 防御 · 韧性控制台」
登录账号 login_id 输入框。autocomplete=username,自动聚焦
密码 password 输入框 + 眼睛图标的显示/隐藏切换
错误横幅 失败时:「账号或密码不正确。」
隐藏字段 next 登录后的返回路径(必须以 / 开头)
提交按钮 「登录 →」

登录表单携带标准的 Blade @csrf 令牌。控制台由会话 + CSRF 保护,界面上不会另外索要 bearer 令牌。

如何使用

登录

  1. 打开 /login(如果已登录,会被重定向到 /)。
  2. 输入你的 Login ID 和 Password。
    • 校验规则:login_id 最长 60 个字符,password 为 4–120 个字符。
  3. 点击 登录。服务器按 login_id + is_close=0 在 infr_user 中查找账号并校验密码。
  4. 成功后会话被重新生成(session()->regenerate()),并跳转到 next(或 /)。

登录成功会写入以下 会话键:

会话键 值
infr_user_id infr_user.id(判断是否已认证的依据)
infr_login_id 登录账号
infr_user_level user_level(整数) — RBAC 级别
infr_name 显示名称
infr_lang 显示语言(默认为 ko)

同时会将 last_log 列更新为当前时间。

退出登录

会话有效期与每次请求的重新同步

每个控制台页面都会经过 infr.auth(InfrAuth),它在每次请求时:

  1. 用会话中的 infr_user_id 重新加载用户(热路径,只取最少的列:id · login_id · name · email · user_level · role_id · team_id · lang · avatar · is_close)。
  2. 如果账号不存在或 is_close=1(已停用),就销毁会话并重定向到 /login(JSON 请求则返回 401)。
  3. 用数据库中的值覆盖 infr_user_level · infr_name · infr_lang — 因此管理员对级别/姓名/语言的修改会从下一次请求起生效,无需重新登录。
  4. 把用户模型放入 infr_user 请求属性,并通过 app()->setLocale() 设置显示语言。
  5. 调用 OpsPolicy::markPresence() 记录 在线状态(运维策略的节能模式用它判断「此刻是否有控制台用户在活动」,并据此控制数据库采集 — 参见 运维策略)。

会话有效期遵循 SESSION_LIFETIME(默认 120 分钟)。

控制台登录没有单独的「记住我」复选框。会话只在上述有效期内保持,过期后必须重新登录。

外部接入 API 认证(Bearer 密钥)

当外部应用向 /api/v1/* 发送请求时,它使用 API 密钥 认证(无状态 — 没有会话,也没有 CSRF)。

方式 请求头示例
Bearer Authorization: Bearer YOUR_KEY
自定义请求头 X-Infr-Api-Key: YOUR_KEY

行为:

主要端点:

# 连通性/密钥检查
curl -sS https://infraguard.example.com/api/v1/ping \
  -H "Authorization: Bearer YOUR_KEY"

# 自动登记事件(已去重 · source=pulse)
curl -sS -X POST https://infraguard.example.com/api/v1/incidents \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"NPE in checkout","fingerprint":"abc123","severity":"crit"}'

在 管理 ▸ API 密钥 中签发、吊销密钥并复制对接代码(明文密钥 只在签发时显示一次)。

Step-up — 保护破坏性操作

封禁、解封、恢复或修改设置等有风险的操作受到保护 —— 并非通过重新输入密码,而是通过三道防线:

  1. 级别复核 — 写入操作至少需要写入级别(2 以上),管理操作需要管理员(10),并在服务端重新校验。
  2. 审计日志 — 变更前后的值以及操作者和 IP 会被写入 审计日志(infr_audit_log)。
  3. 界面确认 — 界面上有一个确认对话框(step-up)拦在操作之前。

数据来源

对象 用途
infr_user 运维人员账号。列:login_id · password · user_level · name · email · lang · is_close · role_id · team_id · last_log · avatar
会话存储(Redis) infr_user_id 等会话键(REDIS_PREFIX 为 infr_)
infr_api_key 接入 API 密钥的 哈希(key_hash) · is_active · use_count · last_used_at/ip
infr_audit_log 破坏性/安全操作的审计轨迹

infr_user.password 列绝不会出现在日志、URL 或 Cookie 中。API 密钥的明文只在签发时显示一次,数据库只保存哈希。

访问权限

URL 级别的门槛(登录后评估):

区域 中间件 最低级别
常规控制台(概览 · 基础设施 · 资产只读) infr.auth 仅需登录(1)
/security · /backup infr.level:2 2
/admin infr.level:10 10
/horizon · /pulse infr.admin 10
开发区 infr.dev 9

级别档位:demo=1 · staff=5 · admin=10。完整策略参见 访问级别。

排障与 FAQ

我登录了,却一直被弹回 /login。 会话 Cookie 没有被保存(域名与 SESSION_DOMAIN 不匹配,或者仅限 HTTPS 的 Cookie 通过 HTTP 下发),或者账号被设为 is_close=1(已停用)。请让管理员检查账号状态。

我看到「账号或密码不正确。」 login_id 拼错、密码不对,或者账号已停用(is_close=1)。出于安全考虑,提示不会说明具体是哪一种。

账号无法登录。 可能是密码不正确或账号已被停用。请管理员在 用户与团队 中重置密码。

我能登录,但打不开 /admin。 你的级别低于 10。/admin 由 infr.level:10 把守,只有管理员才能进入。同样,/security 和 /backup 需要 2 级以上。

AJAX 调用返回 401。 控制台会话已过期。刷新页面并重新登录。JSON 请求收到的是 {"error":"unauthenticated"} 401,而不是重定向。

管理员提升了我的级别,却没有生效。 InfrAuth 在每次请求时都会重新同步会话,因此 从下一次页面跳转起 生效 — 无需重新登录。刷新即可立即生效。

菜单/界面显示成了意料之外的语言。 显示语言取自 infr_user.lang(会话中的 infr_lang),并在每次请求时重新同步。可在 本地化 中修改。

API 返回 401 invalid_api_key / 429 rate_limited。 密钥被停用或拼错会得到 401;每分钟超过 120 次请求会得到 429(+ Retry-After)。请在 API 密钥 中检查密钥状态并放慢调用频率。

相关条目

로그인 화면
로그인 화면