作品索引

Nexus ID - 多租户身份与 OIDC 平台

GoGinPostgreSQLRedisNuxt 4OIDCWebAuthnOpenTelemetry
Nexus ID - 多租户身份与 OIDC 平台

Nexus ID 是一套面向企业应用的统一身份中心。它不只负责“用户名加密码换 JWT”,还把租户、控制台操作员、终端用户、应用授权、会话撤销、MFA、OIDC 和审计放进同一个安全边界里。

这个项目最重要的决定,是把安全上下文当成业务主线:一次请求先确定“谁在访问、代表哪个租户、以什么角色访问”,再允许它读取数据或改变状态。协议能力只是入口,租户边界、令牌生命周期和可追溯性才是身份平台能否长期运行的基础。

Nexus ID 统一身份中心总体架构

先分开控制面与终端身份

Nexus ID 现在明确区分两类账户:operator_accounts 是登录 SaaS 控制台的人,users 是租户内的终端身份。控制台账户通过 tenant_members 加入租户,成员角色为 owneradmindeveloperviewer;终端用户则拥有自己的应用授权、部门、职位、第三方账号和会话。

这条边界解决了早期统一用户表最容易出现的混乱:管理员不再因为拥有某个终端用户角色,就自动获得所有租户的超级权限;租户成员也不等同于业务应用中的登录用户。邀请 token 只保存 SHA-256 摘要,接受邀请和切换租户都会重新校验当前成员关系。

控制台负责租户、成员、应用、OIDC Client、Webhook、邮件模板和运营设置;终端用户入口负责注册、登录、个人资料、应用授权、第三方绑定、会话和安全设置。两条链路共用底层服务,但不共用身份、Cookie 或会话语义。

一次请求如何获得安全上下文

所有 /api/v1 请求先经过 Gin 中间件链:request id、OpenTelemetry、HTTP 指标、结构化日志、恢复、语言、CORS、传输加密、限流和统一错误信封。认证中间件验证 token 或控制面 session 后,才会把当前用户、operator、tenant 和 member role 写入 TenantContext

tenant-scoped repository 不直接从连接池拿一个裸 Queries 执行 SQL,而是通过 TenantExecutor 开启短事务,并执行 transaction-local 的 set_config('app.tenant_id', ...)。查询仍然显式携带 tenant_id,PostgreSQL 的 FORCE ROW LEVEL SECURITYWITH CHECK 则作为遗漏过滤时的最终防线。运行角色没有 SUPERUSERBYPASSRLS 或租户表 owner 权限;迁移、回填和系统级维护使用独立的受控 capability。

这是一种纵深防御,而不是把 RLS 当成一句配置口号。应用层的查询意图可审查,数据库层可以阻断一次漏写条件,A/B 租户 fixture 则验证读取、更新、删除、成员邀请和 OIDC 数据都不能跨边界。

登录之后,才开始真正的身份生命周期

登录入口不止密码:当前服务同时提供第三方 OAuth、Passkey、扫码登录和原生客户端邮箱验证码。密码、OAuth 或 Passkey 通过后,如果账号或租户启用了 MFA,服务端不会直接签发会话,只会在 Redis 中放入五分钟、一次性消费的 mfa_ticket。用户必须完成 TOTP 或一次性恢复码挑战,失败会作废票据并记录安全事件。

TOTP 按 RFC 6238 校验,并记录已接受的时间步,阻止同一窗口内的验证码重放;恢复码只存哈希且只能消费一次。控制台操作员有独立的 MFA 票据和 15 分钟 step-up 窗口,敏感的租户、成员、密钥和授权变更不能只凭一个长时间未验证的登录状态。

Nexus ID 登录、MFA 与会话生命周期

会话的事实来源是 PostgreSQL sessions,Redis 只缓存活动或撤销状态。终端用户 access token 使用每租户的 RS256 密钥签名,默认 TTL 为数分钟,claims 带 kidtenant_idsession_id,资源服务器可以从 JWKS 离线验证。refresh token 是不透明值,数据库只保存 SHA-256 哈希,每次刷新都会轮换并记录 family/parent 链;旧 token 再次出现会吊销整个 family 和所属会话,而不是简单返回一次错误。

浏览器模式下 refresh token 通过 HttpOnly + Secure + SameSite Cookie 交付,刷新请求还必须通过 Origin/Referer 与双提交 CSRF 校验;access token 只留在内存。登出、改密、重置密码、禁用用户和暂停租户都会撤销关联会话,Redis 不可用时高权限会话校验按 fail closed 处理。

把统一登录变成标准 OIDC

Nexus ID 使用 zitadel/oidc 的协议实现,按租户提供独立 issuer:

text
{issuer_base_url}/oidc/{tenant-slug}

每个 issuer 暴露 discovery、JWKS、/authorize/oauth/token/userinfo/oauth/introspect/revoke/end_session。public client 强制 Authorization Code + PKCE S256;confidential client 的 secret 只在创建或轮换时显示一次,数据库只保存哈希和状态。redirect URI 精确匹配,不允许通配符;授权码只存哈希,绑定 client、redirect、PKCE、nonce 和 session,TTL 两分钟且原子消费。

Hosted Login 通过 opaque 的 authorization request id 与业务前端衔接:用户在 Nexus ID 页面完成密码、第三方登录、MFA 和 consent 后,服务端确认用户与 pending request 属于同一租户,再让协议库回跳到已登记的 callback。scope 扩大需要重新 consent,拒绝也会带着原始 state 返回 RP。OIDC refresh grant 复用第一方会话与 refresh rotation,不维护第二套令牌家族。

Nexus ID 多租户 OIDC 授权与数据隔离

OIDC access token 的 jti 会在 Redis 中登记,introspection 必须同时通过 JWT 校验并命中登记,撤销后可以立即返回 active: false;只做离线验证的资源服务器则依靠 60 到 900 秒的短 TTL 收敛。

应用授权与外部 API

除了 OIDC Client,平台还保留面向内部系统的 API Client 管理:一个 client 可以绑定允许访问的内部应用,再通过 method + path_pattern + scope 授予接口级权限,并附加 IP、用户过滤条件和限速。请求进入外部 API 后先校验凭证,再检查应用范围和接口权限,所有结果进入审计日志。

兼容的 HMAC-SHA256 请求会把 method、path、timestamp、nonce 和 body 组成 canonical request,Redis 负责一次性 nonce,可信代理和 IP allowlist 共同限制来源。API Client 绑定可访问的内部应用、接口权限和 scope,鉴权结果统一进入审计日志。

审计不是请求日志的副产品

Nexus ID 将两种记录分开处理:结构化 HTTP 日志用于排查请求,security_events 用于回答“谁在什么时候以哪个 tenant、session、client 做了什么”。登录成功/失败、MFA challenge、refresh 重放、会话撤销、OIDC 授权批准/拒绝、consent 和密钥操作都进入安全事件。

日志入库前会递归脱敏密码、token、验证码和 secret;租户内审计序列维护 hash chain,数据库 trigger 将日志表设为 append-only,管理员可以通过链校验接口发现删除或插入。控制面写操作先写 attempt 审计,审计不可用时返回 503,而不是悄悄完成一次无法追溯的权限变更。

邮件验证码、邀请、登录告警和 Webhook 由后台 worker 投递,失败任务可重试。Prometheus 和 OpenTelemetry 覆盖 HTTP、认证、限流、数据库和 Redis 健康;/livez/readyz/metrics 用于容器和 systemd 的运行检查。敏感配置可在启动前由 OpenBao Transit 解密,Docker Compose 提供 PostgreSQL、Redis、后端和 Nuxt 前端的本地编排。

实现与验证

仓库通过自动化测试覆盖多租户 TenantExecutor 与 RLS、RS256/JWKS、会话和 refresh rotation、TOTP 与恢复码、控制面 MFA、OIDC Authorization Code + PKCE、审计 hash chain、Redis 限流和 CI 门禁。项目同时提供 OpenAPI、SPA PKCE 示例、confidential web 示例、迁移工具、seed、租户回填和 Linux 部署 runbook。

这个项目想解决的不是“再做一个登录页”,而是把身份系统中的关键问题放进主链路:租户如何隔离,管理员与终端用户如何分开,token 如何撤销,MFA 如何防重放,OIDC 如何遵守标准,授权变化如何留下证据。Nexus ID 将这些能力组合成一套统一身份平台,为控制台、终端用户和业务应用提供一致的认证与授权基础。