feat(fam-core): 登录改接 auth-hub 统一登录(OAuth2 Authorization Code + PKCE / OIDC)

移除本地 FAM_AUTH_USER/PASS 账号密码校验和内置登录表单,/login 改为 302
跳转 auth-hub /authorize,新增 /api/auth/callback 完成 code 换 token +
id_token 签名验证(PyJWT + JWKS),验证通过后种回原有 fam_session cookie,
is_authed()/全局登录拦截逻辑不变。接入参数走环境变量,未配置齐全 fail
closed。本地起 auth-hub 开发实例 + 真实浏览器验证过完整登录/登出闭环。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ericwyuan
2026-08-31 21:32:26 +08:00
parent 988c63a8f9
commit 8120d2ae6a
6 changed files with 399 additions and 155 deletions

View File

@@ -1,17 +1,34 @@
# 项目进度追踪
> 最后更新: 2026-08-28
> 最后更新: 2026-08-31
## 服务运行状态
| 服务 | 节点 | 地址 | 状态 | 验证结果 |
|------|------|------|------|---------|
| FAM-Core | NAS | 0.0.0.0:8000 | ✅ 运行中 | health=ok, gunicorn 单 workerOracle-Sync + MotionNotifier 轮询 SS 事件推送(游标 DB 续用/失败重试);已部署事件时间轴删除功能;`/api/status`/`/api/ss/status` 500 bug 已修复 |
| FAM-Core | NAS | 0.0.0.0:8000 | ⚠️ 代码已完成,待生产部署 | health=ok, gunicorn 单 workerOracle-Sync + MotionNotifier 轮询 SS 事件推送(游标 DB 续用/失败重试);已部署事件时间轴删除功能;`/api/status`/`/api/ss/status` 500 bug 已修复**登录改接 auth-hub 统一登录OIDC本地全链路验证通过生产 client 注册 + NAS `.env` 配置 + 部署重启尚未执行** |
| FAM-Edge | Oracle新机 129.146.26.249 | 0.0.0.0:5000 | ✅ 运行中 | systemd 守护fam-edge.service素材→运动片段分割→只分析片段问答改为转发 AI-Gateway队列消费正常已部署 `/api/oracle/video/delete`FFmpeg 已补装;新增 DiskGuard 磁盘守护 |
| **AI-Gateway** | Oracle | 0.0.0.0:5100 | ✅ 运行中 | systemd 守护ai-gateway.service2026-08-23 新增;独立仓库/独立部署;`/health` 正常端到端问答实测成功provider=nvidia |
| MariaDB | NAS | 127.0.0.1:3306 | ✅ 运行中 | 10.11.11, 6 张表, utf8mb4 |
| Ollama | Oracle | 127.0.0.1:11434 | ✅ 运行中 | qwen2.5:7b仅智能问答兜底不参与视觉/融合);**被 AI-Gateway 调用,不再被 FAM-Edge 直接调用** |
## 2026-08-31 FAM-Core 接入 auth-hub 统一登录OIDC
- **背景**:独立的统一登录/SSO 服务 [auth-hub](http://129.146.26.249:3000/ericwyuan/auth-hub)(跟本项目完全独立的仓库/数据库/部署OAuth2 Authorization Code + PKCE + OIDC已单独开发验证完成本地全链路 47 单测通过目标是自己的几个网站统一接到这一处身份服务不用每个网站各自维护一份账号密码。FAM-Core 是第一个接入方。
- **改造范围**`fam-core/src/fam_core/auth.py` 全量重写commit 待提交):
- 原来自己校验 `FAM_AUTH_USER`/`FAM_AUTH_PASS` 的账号密码逻辑、内置深色登录表单页全部移除;`GET /login` 改为直接 302 跳转 auth-hub `/authorize`(带 PKCE `code_challenge`/`state`,均存进程内 `_pending`10 分钟过期)
- 新增 `GET /api/auth/callback`:收 auth-hub 回跳的 `code`,服务端到服务端 `POST /token``id_token`(用 `PyJWT` + `PyJWKClient` 拉 auth-hub JWKS 验 RS256 签名 + `iss`/`aud`),验证通过后种回原有的 `fam_session` HttpOnly cookie**2 小时有效,机制不变**)——下游 `is_authed()`/`init_auth()` 全局拦截逻辑完全没动
- 接入参数 `AUTH_HUB_ISSUER`/`AUTH_HUB_CLIENT_ID`/`AUTH_HUB_CLIENT_SECRET`/`AUTH_HUB_REDIRECT_URI` 走环境变量NAS `.env`,沿用 `FAM_AUTH_*` 时代"未配置齐全直接拒绝所有登录"的 fail-closed 取舍),`AUTH_HUB_REDIRECT_URI` 必须与 auth-hub 端 `manage_clients create` 登记的 redirect_uri 逐字符一致
- `requirements.txt` 新增 `PyJWT>=2.8.0``cryptography>=42.0.0`
- **访问控制取舍(用户明确决策)**:不在 fam-core 侧加用户名白名单——任何在 auth-hub 上(自助注册 + 管理员审批后)拥有账号的人登录后都能访问本系统;不保留 `FAM_AUTH_USER`/`FAM_AUTH_PASS` 作为备用登录方式SSO 是唯一入口
- 测试:`tests/test_auth.py` 全量重写PKCE 生成、state 校验、token 交换成功/失败、id_token 验签失败、白名单、`before_request` 拦截fam-core 全量 39/39 通过
- **端到端验证(本地)**:本地起了一份 auth-hub 开发实例(:5300+ 一个仅含 `auth_bp` 的最小 Flask 壳子(模拟 fam-core跳过 MariaDB 依赖),用真实浏览器走完整 Authorization Code + PKCE 闭环——`/` 未登录 302 `/login` → auth-hub 登录页 → 登录成功回跳 `/api/auth/callback` → 换 token + 验签 → 种 cookie → 落地首页;`/api/auth/check` 确认 cookie 生效;`/api/logout` 确认清会话。验证完把临时创建的 OAuth client 和测试账号都从 auth-hub 本地库删掉了。
- **未完成(需要生产部署,本次会话未执行)**
1. 在 Oracle 生产 auth-hub`/opt/auth-hub`:5300上用 `python -m auth_hub.manage_clients create "FAM-Core" "http://129.146.26.249/api/auth/callback"` 注册正式 client拿到生产 `client_id`/`client_secret`
2. NAS `.env` 补上 `AUTH_HUB_ISSUER=http://129.146.26.249:5300``AUTH_HUB_CLIENT_ID``AUTH_HUB_CLIENT_SECRET``AUTH_HUB_REDIRECT_URI=http://129.146.26.249/api/auth/callback`
3. 部署新代码到 NAStar 管道,见 `docs/DEPLOY.md` §3`bash start_core.sh` 重启
4. 生产环境浏览器实测一遍完整登录闭环
## 2026-08-28 Oracle 迁移故障排查FFmpeg 缺失 + 磁盘写满死循环 + DiskGuard
- **触发**:用户反馈事件时间轴历史图片丢失、"谷歌同步是不是有问题"。逐层排查,发现的是三个叠在一起的独立问题,不是一个: