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

@@ -320,8 +320,9 @@ chat_history 独立表(问答上下文摘要留存)
| 端点 | 方法 | 说明 |
|------|------|------|
| `/health` | GET | 服务健康(**免登录** |
| `/api/login` | POST | 登录`{"username","password"}` → 校验 `FAM_AUTH_USER`/`FAM_AUTH_PASS`NAS `.env` 配置,无硬编码默认值,未配置则拒绝所有登录)→ 种 HttpOnly cookie `fam_session`2 小时 |
| `/api/logout` | POST | 退出登录(清 cookie |
| `/login` | GET | 登录入口302 跳转 auth-hub `/authorize`Authorization Code + PKCE**免登录** |
| `/api/auth/callback` | GET | auth-hub 登录回跳:拿 `code` 换 token、验 `id_token` 签名后种 HttpOnly cookie `fam_session`2 小时,**免登录** |
| `/api/logout` | POST | 退出登录(清本地 cookie不影响 auth-hub 上的登录态) |
| `/api/auth/check` | GET | 登录态检查:`{"authed": true\|false}`**免登录** |
| `/api/status` | GET | Oracle-Sync + MotionNotifier 状态sync running/cursormotion poll_enabled/pushed_total/heartbeat |
| `/api/chat/ask` | POST | 用户问答:`{"question","queried_person","queried_date"}``{"answer","context_summary","chat_id"}`(上下文来自 sync_events |
@@ -539,7 +540,7 @@ task_id=28930s 测试片段)全链路打通:推送 5.7MB → Edge 分析
| 组件 | 节点 | 路径 | 启动 |
|------|------|------|------|
| FAM-Core | NAS | `/volume1/web/sentinel-home-ai/fam-core/` | `bash start_core.sh`gunicorn -w 1 :8000source .env 注入 DSM_*/ORACLE_SYNC_TOKEN/FAM_AUTH_* |
| FAM-Core | NAS | `/volume1/web/sentinel-home-ai/fam-core/` | `bash start_core.sh`gunicorn -w 1 :8000source .env 注入 DSM_*/ORACLE_SYNC_TOKEN/AUTH_HUB_* |
| FAM-UI | NAS | `/volume1/web/sentinel-home-ai/fam-ui/dist/` | Vue3 构建产物,由 FAM-Core `static_app.py` 托管(无需独立进程);本地改代码后 `npm run build` 并 tar 部署 dist |
| FAM-Edge | Oracle | `/opt/fam-edge/` | **systemd `fam-edge.service` 守护**Restart=always部署代码后 `sudo systemctl restart fam-edge`(勿手动 setsid会端口冲突 |
| **AI-Gateway** | Oracle | `/opt/ai-gateway/` | **systemd `ai-gateway.service` 守护**Restart=always独立 venvPython 3.8gunicorn 绑定 `0.0.0.0:5100`(对外直接开放,非仅本机);部署代码后 `sudo systemctl restart ai-gateway` |
@@ -547,9 +548,9 @@ task_id=28930s 测试片段)全链路打通:推送 5.7MB → Edge 分析
> **外网访问frp 内网穿透)**NAS 跑 `frpc``/etc/frp/frpc.toml`S99frpc.sh 守护),映射到云服务器 `129.146.26.249`frps :7000
> - `3000` → NAS Gitea、`8500` → NAS WordPress(8088)、**`8000` → NAS FAM-Core本系统**
> - 前端入口 `http://129.146.26.249/`Caddy 托管 FAM-UI/api 经 frp 隧道反代回 NAS FAM-Core :8000**需登录**(见 §5.2 `/api/login`
> - 前端入口 `http://129.146.26.249/`Caddy 托管 FAM-UI/api 经 frp 隧道反代回 NAS FAM-Core :8000**需登录**(见 §5.2 `/login`
>
> **登录校验2026-08-22 新增2026-08-23 改为 fail-closed**FAM-Core 全站拦截`auth.py`)——页面未登录 302 `/login`内置深色登录页SPA 零改动)`/api/*` 未登录 401凭据 `FAM_AUTH_USER`/`FAM_AUTH_PASS`NAS `.env` 配置,**无硬编码默认值**——这两个变量跟 NAS SSH 密码是同一个值,公网入口不能有"没配置就退回已知密码"的兜底,`.env` 没配好这两项时直接拒绝所有登录);白名单免登录:`/login` `/api/login` `/api/logout` `/api/auth/check` `/health` `/assets/*``/api/ss/webhook` 已随端点一起移除2026-08-25登录态为进程内 token + HttpOnly cookie**2 小时**),过期或重启 fam-core 需重新登录
> **登录校验2026-08-22 新增2026-08-23 改为 fail-closed2026-08-31 接入 auth-hub 统一登录)**FAM-Core 不再自己保存/校验密码,全权委托给独立部署的 [auth-hub](http://129.146.26.249:5300)OAuth2 Authorization Code + PKCE / OIDC同一 Oracle 主机 :5300与本系统完全独立部署——`/login` 302 跳到 auth-hub `/authorize`,登录后带 `code` 跳回本服务 `/api/auth/callback`,服务端换 token、验完 `id_token` 签名JWKS后种本地会话 cookie。全站拦截仍在 `auth.py`页面未登录 302 `/login``/api/*` 未登录 401接入参数 `AUTH_HUB_ISSUER`/`AUTH_HUB_CLIENT_ID`/`AUTH_HUB_CLIENT_SECRET`/`AUTH_HUB_REDIRECT_URI`NAS `.env` 配置,**无硬编码默认值**任一没配置直接拒绝所有登录fail closed`AUTH_HUB_REDIRECT_URI` 必须与 auth-hub 用 `manage_clients create` 登记的 redirect_uri 逐字符一致auth-hub 只做精确匹配,不做前缀/子串匹配)。白名单免登录:`/login` `/api/auth/callback` `/api/logout` `/api/auth/check` `/health` `/assets/*``/api/ss/webhook` 已随端点一起移除2026-08-25本地会话仍是进程内 token + HttpOnly cookie**2 小时**),过期或重启 fam-core 需重新走一遍 auth-hub 登录auth-hub 侧注册是任何人都能自助注册(管理员审批后才能登录),**未对 fam-core 侧再加用户名白名单**——任何在 auth-hub 上审批通过的账号登录后都能访问本系统,这是有意识的取舍(自用场景,见项目记忆)
> Oracle 部署方式:本地 git 提交 push Gitea → tar 管道到 `/opt/fam-edge``--strip-components=1` 解临时目录再 cp避免动 data/venv/gdrive_videos。**AI-Gateway 是独立 git 仓库**http://192.168.50.64:3000/ericwyuan/ai-gateway见 §10.4),同样 tar 管道部署到 `/opt/ai-gateway`,互不影响。