e482f8860049f2cc1ada9e4ca12182a215e6ec05
造物工坊 · Foundry Core
共享后端的第一版提供 Google 登录。各项目通过同一个 HTTPS API 登录,在私有 PostgreSQL 的认证库中维护独立账号和会话。项目业务库可分别配置独立的数据库和角色。
服务端配置
- 在 Google Cloud 创建一个 Web application OAuth 客户端。授权重定向 URI 填写
https://<API 域名>/auth/google/callback。所有项目信任同一个客户端,因此共享 Google 同意页面的应用名称。 - 在服务器私网准备 PostgreSQL。在认证库执行一次
db/001-auth.sql(使用psql -v ON_ERROR_STOP=1),给运行账号授予这四张表所需的查询及增删改权限。 - 按
.env.example注入运行环境变量。每个项目配置一个固定的前端回调地址,本地开发可用 localhost。将 Google 客户端密钥和数据库连接串存入服务器的密钥管理设施。 - 在已确认的远程 runner 上安装生产依赖。运行 Node.js 22 或以上版本,通过 HTTPS 反向代理转发至服务监听地址。通过
GET /healthz检查进程,通过GET /readyz检查认证库。 - 代理避免记录 Google 回调的查询参数及认证请求头。设置入口限流,并定时删除三张临时表(
oauth_attempts、login_grants、project_sessions)中expires_at <= now()的记录。
前端接入
- 在浏览器用 Web Crypto 生成 32 字节随机值,编码为无填充 Base64URL,作为 verifier 暂存在当前 tab 的 sessionStorage。对 verifier 字符串做 SHA-256 并用相同编码得到 challenge。
- 顶层导航到
GET /projects/<project>/auth/google?challenge=<challenge>。Google 回到共享 API 后,API 将浏览器重定向至已配置的项目回调。 - 回调页从 URL fragment 读取
code或error,用 history.replaceState 清掉 fragment。收到 code 时,向POST /projects/<project>/auth/exchange发送X-Foundry-Code和X-Foundry-Verifier请求头,随后清理暂存的 verifier。code 有效期一分钟,仅可使用一次。 - 将返回的八小时会话凭证保存在内存中,使用
Authorization: Bearer <access_token>调用GET /projects/<project>/auth/me。通过POST /projects/<project>/auth/logout撤销会话并清理本地凭证。刷新页面后,内存凭证需要通过重新登录获取。
同一个 Google 账号首次进入不同项目时,会分别创建用户 ID。会话绑定其签发项目。Google 账号的标识 sub 用于认领同一项目的既有账号,邮箱只作为资料字段。当前注册模式为开放注册。
验收
用同一个 Google 测试账号分别登录两个项目,确认用户 ID 不同。用 A 的会话请求 B 的 me 应返回 401。验证兑换码重放被拒绝,并确认退出 A 后 B 的会话仍有效。
Description
Languages
Go
83.4%
PLpgSQL
7.5%
Shell
7.2%
Python
1.9%