Files
probably-rendering-one-more…/docs/dynamic-code-login.md
T
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

3.6 KiB

动态码登录与 SSH 绑定

生产全站使用共享验证器的 6 位动态码登录,无账号密码。它是单因素 TOTP 登录,不是两个因素的 2FA。每 30 秒更新,允许前后一个时间步偏差。登录后签发 HS256 JWT,保存在 HttpOnly、SameSite=Lax Cookie 中,有效期 7 天,不放 localStorage。

管理员扫码

SSH 登录部署服务器,在交互终端执行(不要放到 CI、日志或重定向到文件):

sudo /opt/prompt/auth qr

手机用 Google Authenticator、Microsoft Authenticator 或其他 TOTP 验证器扫描终端二维码。多人可以分别扫同一张二维码;动态码相同,不能区分操作人。不要把二维码发到公开聊天或网页。二维码不通过任何 HTTP 接口提供,也不写入源码或镜像;服务器 Docker 卷 prompt_auth_data 持久保存密钥,应用只读挂载,配置文件权限 0600、目录 0700。更新和容器重启不会更换二维码。

也可以从电脑直接执行(SSH 用户按自己的服务器配置替换):

ssh -t <服务器用户>@8.211.154.134 'sudo /opt/prompt/auth qr'

网站只需输入当前动态码。验证码成功使用后不能再次使用;多人同时登录时,后登录者需等下一组动态码。全站共用每 5 分钟最多 20 次尝试的限额,计数与已用时间步保存在 PostgreSQL 中,容器重启不会重置。

丢失手机、撤销访问或密钥泄漏

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 不应删除;回退旧版本将恢复原来的匿名访问行为。