Feature: Add admin-only SSO bridge to web UI
Bridge an already-authenticated portal session into a YAMA web session via a new /sso endpoint, so portal administrators can enter the remote-desktop UI without a second login. Only the "admin" portal role is bridged; any other role (viewer, unknown) still falls back to the built-in login form, so a low-privileged portal account cannot bypass authentication. - wsauth: extract IssueToken from VerifyLogin so an out-of-band-authenticated identity (SSO) can mint a session token without the challenge/response. - web: add the SSODetector interface, a fail-closed JWT detector (HMAC-only), and the /sso handler gated to the admin role. - cmd: enable the JWT detector via YAMA_SSO_JWT_SECRET, the shared HS256 secret matching the parent portal. - web UI: attempt SSO before showing the login form, falling back to login when the server returns 401. - docs: document SSO (admin-only) and license trial-vs-paid troubleshooting in README and the env example. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
1 parent
d2149851b2
commit
53b7151fb7
9 files changed
+499
-11
No files matched your search
@@ -170,6 +170,7 @@ VSCode F5 调试时由 `sync-web-assets` preLaunchTask 自动同步。
|
||||
| `YAMA_USERS_FILE` | Path to the JSON file that persists non-admin web users (allowed_groups, password hash, salt). Default is `users.json` in the working directory. | `users.json` |
|
||||
| `YAMA_WEB_ALLOWED_ORIGINS` | Comma-separated WebSocket Origin allowlist for cross-origin upgrades. Empty (default) → only same-origin upgrades are accepted, which is correct when the web UI and `/ws` share a host. Add an entry per trusted PWA / dev origin. | `https://yama.example.com,https://yama-mobile.example.com` |
|
||||
| `YAMA_WEB_TRUST_PROXY` | Set to `1` only when running behind a reverse proxy you control (caddy / nginx / cloudflare). Switches client-IP extraction to use the last entry of `X-Forwarded-For` instead of `RemoteAddr`, so per-IP login rate limit sees the real client. Direct-exposure deployments MUST leave this unset — otherwise attackers can spoof the header to evade rate limits. | `1` |
|
||||
| `YAMA_SSO_JWT_SECRET` | **[SSO]** Shared HS256 secret for bridging the parent portal's `auth_token` JWT into a YAMA web session via `/sso`. Must equal the upstream portal's signing key (FMS: `SERVER_PRIVATE_KEY`). **Only `admin` portal users are auto-logged-in**; other roles still need YAMA's own web login. Unset → SSO disabled, `/sso` returns 401. | `<shared-secret>` |
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
@@ -598,6 +599,52 @@ nohup ./server_linux_amd64 -p 6543 --http-port=8080 --no-console &
|
||||
- 受管设备的 `client.exe` 由 Windows 主控端生成(已绑定服务端地址和公钥),下级运营商把它分发给终端用户。
|
||||
client 通过 6543 端口连接到本服务端;用户通过 8080 端口登录 Web 管理页面。
|
||||
|
||||
### 验证与排障
|
||||
|
||||
下级服务是否真的拿到付费授权,两侧各看一行日志即可定位:
|
||||
|
||||
| 现象 | 授权中心日志(`logs/server.log`) | 下级启动日志 | 结论 |
|
||||
| ---- | -------------------------------- | ------------ | ---- |
|
||||
| 付费生效 | `License Server: signed for sub=<客户名> ... active=N/M ttl=...` | `Signer mode: REMOTE (paid customer, ...)` | ✅ 正常 |
|
||||
| 匿名试用 | `License Server: signed for sub=trial:<下级出口IP> ...` | `Signer mode: TRIAL (...)` | ⚠️ 下级没读到 `YAMA_LICENSE_TOKEN` |
|
||||
| token 无效 | nginx access.log 里 `/license/sign` 回 `401` | `Signer mode: REMOTE` 但设备连不上 | ⚠️ token 过期 / 密钥不匹配 / 被篡改 |
|
||||
|
||||
**关键区分**:`sub=trial:<IP>` 表示下级请求**根本没带 `Authorization` 头**(token 为空,等于没读到),
|
||||
而不是 token 错 —— token 错会返回 401。两者根因不同,别误判成「token 配错了」。
|
||||
|
||||
#### systemd 改 env 文件后不生效(最常见坑)
|
||||
|
||||
`EnvironmentFile=` 只在服务**启动那一刻**读一次,改文件不会热更新,必须重启服务。典型表现就是
|
||||
改了 `YAMA_LICENSE_TOKEN` 后日志仍显示 `Signer mode: TRIAL`。
|
||||
|
||||
```bash
|
||||
# 1. 确认运行中的进程到底有没有读到该变量(这才是真相)
|
||||
PID=$(systemctl show <服务名> -p MainPID --value)
|
||||
tr '\0' '\n' < /proc/$PID/environ | grep -i YAMA_LICENSE_TOKEN || echo "进程里没有该变量"
|
||||
|
||||
# 2. 重启后再验一次 + 看启动日志
|
||||
systemctl daemon-reload && systemctl restart <服务名>
|
||||
journalctl -u <服务名> --no-pager -n 40 | grep -iE "signer mode"
|
||||
```
|
||||
|
||||
下级日志出现 `Signer mode: REMOTE` 说明 token 已读入;授权中心日志出现 `sub=<客户名>` 即全链路闭环。
|
||||
|
||||
### SSO(单点登录,可选)
|
||||
|
||||
Web UI 挂在已有域名(如 FMS 网关)的 `/remoter` 子路径下时,可让**已登录门户的管理员免二次登录**直接进远程桌面管理页。设 `YAMA_SSO_JWT_SECRET`(= 上游门户的 HS256 签名密钥,FMS 即 `SERVER_PRIVATE_KEY`)后启用:
|
||||
|
||||
```bash
|
||||
export YAMA_SSO_JWT_SECRET="与上游门户一致的共享密钥"
|
||||
```
|
||||
|
||||
行为:
|
||||
|
||||
- `/sso` 校验浏览器携带的 `auth_token` cookie(或 `Authorization: Bearer`),通过后铸一枚 YAMA 自己的会话 token 返回给前端。
|
||||
- **只有 `admin` 角色的门户用户会被自动登录**;其他角色(viewer / 未知)即使已登录门户,`/sso` 仍返回 401,前端回退到 YAMA 自带的 Web 登录表单,必须再输一遍 YAMA 的登录密码。
|
||||
- 未配置 `YAMA_SSO_JWT_SECRET` 时 `/sso` 恒 401,行为等同纯本地登录。
|
||||
|
||||
注意:SSO 只桥接「识别门户身份」,YAMA 本地登录(账号 + 密码)始终保留作为兜底;自动登录后的角色权限仍由 YAMA 自己的账号体系决定。
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
Reference in new issue
Block a user