Files
probably-rendering-one-more…/docs/dynamic-code-login.md
codex-bot 0c1ed2d292
studio CI and deployment / verify-and-deploy (push) Successful in 1m14s
wiki CI and deployment / verify-and-deploy (push) Failing after 25m6s
Add SSH-provisioned TOTP login with JWT sessions
2026-10-27 00:12:12 +08:00

47 lines
3.6 KiB
Markdown

# 动态码登录与 SSH 绑定
生产全站使用共享验证器的 6 位动态码登录,无账号密码。它是单因素 TOTP 登录,不是两个因素的 2FA。每 30 秒更新,允许前后一个时间步偏差。登录后签发 HS256 JWT,保存在 HttpOnly、SameSite=Lax Cookie 中,有效期 7 天,不放 localStorage。
## 管理员扫码
SSH 登录部署服务器,在交互终端执行(不要放到 CI、日志或重定向到文件):
```sh
sudo /opt/prompt/auth qr
```
手机用 Google Authenticator、Microsoft Authenticator 或其他 TOTP 验证器扫描终端二维码。多人可以分别扫同一张二维码;动态码相同,不能区分操作人。不要把二维码发到公开聊天或网页。二维码不通过任何 HTTP 接口提供,也不写入源码或镜像;服务器 Docker 卷 `prompt_auth_data` 持久保存密钥,应用只读挂载,配置文件权限 0600、目录 0700。更新和容器重启不会更换二维码。
也可以从电脑直接执行(SSH 用户按自己的服务器配置替换):
```sh
ssh -t <服务器用户>@8.211.154.134 'sudo /opt/prompt/auth qr'
```
网站只需输入当前动态码。验证码成功使用后不能再次使用;多人同时登录时,后登录者需等下一组动态码。全站共用每 5 分钟最多 20 次尝试的限额,计数与已用时间步保存在 PostgreSQL 中,容器重启不会重置。
## 丢失手机、撤销访问或密钥泄漏
```sh
sudo /opt/prompt/auth rotate --confirm
sudo /opt/prompt/auth qr
```
轮换会同时使所有人的旧验证器及现有 JWT 失效,需要所有人重新扫码。恢复权限依赖服务器 SSH 管理权,没有公开重置入口。退出登录清除本机 Cookie;已复制的 JWT 在过期或密钥轮换前仍有效。
## 自动化和健康检查
除登录页、登录/退出接口、Next.js 代码资源及最小健康检查外,页面、数据接口、媒体、文档及 `/studio` 均要求登录。Studio 直连 18134 端口只绑定回环地址,不能绕过公网入口登录。登录 Cookie 的写入操作校验同源;API 可使用 `Authorization: Bearer <JWT>`。
服务器部署检查通过 `node auth-cli.cjs run <脚本路径>` 在进程内给本机请求加入短期 JWT,不打印令牌。人工自动化可通过 `sudo /opt/prompt/auth token` 在交互终端获取有效 1 小时的令牌,权限等同共享登录,请妥善保存。外部客户端需要自行携带令牌;已有匿名下载/发布脚本需要相应调整。
## HTTP 与 HTTPS
当前入口是 HTTP,为兼容现有地址,首次部署在 `/etc/prompt.env` 添加 `AUTH_COOKIE_SECURE=false`。这只能防止未授权访问,HTTP 仍可能被窃听。启用 HTTPS 后将其改为 `true` 并重新创建 web 容器,使 Cookie 带 Secure。应用默认 Secure;只有明确设置 false 才兼容 HTTP。代理环境必须保留真实 Host 和 Origin。
## CI、部署与回退
Docker CI 先完成原有集成测试,再启用独立测试密钥验证未登录拦截、真实动态码登录、并发重放拒绝、JWT/Cookie、跨站拒绝、限速以及重启后的访问保护。二维码不会输出到 CI 日志。生产部署自动初始化密钥、运行数据库迁移并验证访问保护;失败沿用部署脚本的镜像和数据库备份回退。认证配置损坏或丢失时返回 503,不会开放访问。
手动回退使用 `git revert <本次提交>` 后推送,等待 CI 部署。007 迁移仅新增认证计数表,不修改既有笔记与素材。`prompt_auth_data` 不应删除;回退旧版本将恢复原来的匿名访问行为。