状态:产品与协议实现依据。本文定义人类身份、登录入口、账号绑定、会话、MFA、身份撤销和 App/CLI 回调。设备能否加入 Network 仍由注册、准入与配额协议决定;登录成功本身不创建 Device、Node Membership 或访问 Grant。
| 角色 | 权威事实 | 明确不负责 |
|---|---|---|
| Identity Authority | 账号、登录方式、凭据、MFA、认证强度、用户会话 | Network 准入、设备身份、数据面授权 |
| NSD | Organization、Network、Membership、Enrollment Policy、Grant、审计 | 保存用户密码明文、持有 Device 私钥 |
NS App / ns | 发起浏览器登录、保存本地会话与 Device Key、展示权威状态 | 判断密码、模拟 IdP、按邮箱自行合并账号 |
| 企业 IdP | 企业用户认证、MFA/认证强度、账号生命周期信号 | 直接创建 NSIO Device 或放宽 Grant |
| Enrollment 服务 | 把已验证主体、Device Key、目标和 Policy 组合成一次性准入决议 | 把浏览器 Cookie 当作设备凭据 |
Identity Authority 可以与 NSD 同一部署包交付,但协议和数据边界仍保持独立。更换 Dex、Zitadel、Keycloak、Ory 或其他实现不得要求 App、Enrollment 或 Grant 协议一起升级。
账号注销、Organization 删除、个人/租户导出和 Legal Hold 不由登录协议自行处理,统一进入信任、合规与数据权利工作流;logout 或解绑登录方式不能代替删除。
首屏直接展示可用方式,不先要求所有用户输入邮箱:
交互硬规则:
bootstrap-admin 创建并登录,再配置 SMTP 或企业 OIDC;state、nonce、PKCE、iss、aud、exp,再根据 (issuer, subject) 定位身份;NSIO Next 对外只定义 OIDC。客户仍可在自己的 Identity Authority 后连接 SAML、LDAP 或其他目录,但这些上游协议不进入 App、NSD 业务 API 或 Enrollment 契约。
登录方式不同,但首次创建账号必须落到同一条事务:
(issuer, subject) 查找。未知且已验证邮箱未占用时创建 User 与 binding;邮箱已属于其他账号时不自动合并,引导先登录原账号再绑定;Provider 没有可信 verified email 时要求补做邮箱验证;invited_only 只接受邀请/SCIM 已存在主体,jit 可在已验证域和映射规则内创建 Organization User;(issuer, subject)。Identity User 成功创建后,NSD 才原子创建其 Personal Organization、默认 Network、个人模板和 Organization Membership。任何 Provider 回调失败、邮箱验证失败或重复 binding 冲突都不得留下半个个人空间。Device 与 Node Membership 仍要随后通过 Enrollment Grant commit 创建。
移动端使用系统认证会话和 Universal Link/App Link 回调。回调 URI 必须与包签名、域名关联文件和 PKCE state 同时成立;自定义 scheme 只能作为明确记录风险的兼容回退,不能成为首选。
ns up 默认打开系统浏览器,流程与桌面 App 相同。CLI 监听 loopback 回调并显示明确状态,不把完整 token 打印到终端或 shell history。
ns up --headless 使用 Device Code:
用户在另一台设备登录后看到设备名、OS、短公钥指纹、校验短语、Organization、Network 和请求能力,再选择“确认这是我的设备”或“这不是我发起的”。Device Code 适合有人操作的无头设备,不用于无人值守生产服务器。
服务器、路由器、容器、CI 和自动扩缩容使用受限 Enrollment Key 或 Workload Attestation,不创建人类浏览器会话。生产 Network 可以配置:
推荐生产/服务器 Network 默认 interactive_enrollment=disabled、allowed_ownership=organization。这防止运维人员因为 Device Code 更方便而把生产节点错误注册为个人资产。
外部身份唯一键是:
邮箱、用户名、头像和显示名都是可变属性,不是授权主键。企业 OIDC、Google、GitHub 和未来微信 Connector 都必须产生稳定 issuer + subject;更换邮箱不创建新 User,也不悄悄转移身份。
本地邮箱密码账号由 Identity Authority 自己作为 issuer,并给账号分配不可变 subject。密码使用可升级参数的 Argon2id;服务端不记录可逆密码,不在日志或审计中保存凭据、验证码或重置 token。
用户解绑某个身份来源时:
identity_binding_id 建立的浏览器会话和 Refresh Token Family;企业可以显式启用 continuous_identity_required,把身份重新验证与 Membership 续租绑定。该策略默认关闭;启用前必须显示离线设备和 IdP 故障对网络可用性的影响。
本地身份首版支持 TOTP、恢复码和 WebAuthn 二次因子;Passkey 主登录后续开放。企业 OIDC 的认证强度由受信 Federation Binding 映射 amr、acr 和 auth_time:
acr/amr 可满足哪些 NSIO assurance,默认不信任未知值。修改 Owner、Federation Binding、SCIM、恢复方式、Enrollment Policy、跨组织 Share、公共入口或破坏性撤销前,需要新鲜 step-up。每次 challenge 绑定具体操作、资源、请求 digest 和短 TTL,不能把一次登录 MFA 无限期复用为所有高风险操作的授权。
不同事件不能压成一个“用户失效”布尔:
| 事件 | 会话/Token | Organization Membership | Device | 数据面 |
|---|---|---|---|---|
| 用户普通退出登录 | 撤销当前会话或所选设备会话 | 不变 | 不变 | 默认不变 |
| OIDC Back-channel Logout | 撤销对应 IdP 会话及 token family | 不变 | 不变 | 默认不变 |
| 用户解绑一个登录方式 | 只撤该 binding 派生会话 | 不变 | 不变 | 不变 |
| SCIM deprovision / 管理员确认离职 | 撤销该 Organization 的全部会话与 token family | 撤销该 Organization 的用户 Membership 和派生 Grant | 用户自有设备失去该组织 Membership;组织资产 Device 保留 | 在撤销 SLA 内停止续租并收敛 |
| 企业 Federation Binding Disable | 阻止新登录和续期 | 默认保留,等待管理员选择 | 不变 | 现有短租约按策略到期 |
| Disable and revoke | 撤会话与 token family | 按影响预览撤销派生 Membership/Grant | 组织资产保留 | 在 SLA 内收敛 |
| Google/GitHub 身份需要重新验证 | 控制面会话到期,要求重新登录 | 默认不变 | 不变 | 默认不变 |
| Device 明确撤销 | 撤销该设备控制会话 | 撤销其全部 Membership | Device 进入 revoked | 立即停止新租约,最迟在 peer lease TTL 内收敛 |
SCIM deprovision 的服务端事务至少包含:撤销组织会话、撤销 Refresh Token Family、撤销该组织用户 Membership、停止派生 Grant/peer lease 续签、重编译受影响 peer map 与 DNS、写审计。撤销 Membership 不等于删除 Device:公司笔记本作为 Organization-owned 资产保留,可重新指派并轮换 Node/WireGuard Key。
默认撤销 SLA 为 5 分钟,计算口径是从权威撤销事务提交到最后一份相关 peer 授权失效;高安全 Network 可以配置更短租约。超过 SLA 产生安全告警和可查询 trace,不能只记一条普通日志。
对没有 SCIM 的 Google/GitHub 等身份,Identity Authority 不保存不必要的上游 Refresh Token。identity_revalidation_interval 到期后要求用户再次完成上游登录;这限制新的控制面会话,不默认切断已建立的数据面。
恢复方式是统一账号安全能力,不按地区分叉:
bootstrap-admin 紧急初始化,仅用于不存在可用管理员的安装阶段。注册完成后必须强引导用户配置至少一种不依赖当前登录方式的恢复能力;用户可以稍后完成普通配置,但 Owner/唯一管理员在未设置恢复方式前不能关闭安全提醒。恢复操作必须撤销既有 Refresh Token Family、记录操作者和恢复渠道,并通知其他已验证渠道。
管理员不能查看用户密码、Passkey 私钥、TOTP seed 或完整恢复码。一次性重置链接只允许设置新凭据,不回显旧凭据。
| 部署 | 邮箱密码 | GitHub | Passkey 主登录 | 企业 OIDC | |
|---|---|---|---|---|---|
| NSIO Cloud | 是 | 是 | 是 | 后续 | 按 Organization 配置 |
| 私有部署 | 可选 | 客户自配 OAuth App | 客户自配 OAuth App | 后续 | 是 |
| 隔离部署 | 是 | 否 | 否 | 后续 | 内网 OIDC 可选 |
微信、企业微信、飞书、钉钉、Microsoft、Apple 等通过 Identity Authority Connector 接入。每个 Connector 必须提供稳定 issuer/subject、明确 claim 映射、回调域名、密钥轮换、禁用状态和审计来源;不得把 Provider 特有字段直接写入 ACL 或 Device 表。
新增 Connector 是增加登录方式,不是新增 Enrollment Proof 状态、User 类型或 ACL 主体类型。Provider 暂时不可达时返回可重试错误,不回落到按邮箱自动匹配。
凭据表与 NSD Organization User/Membership 表分离。NSD 只保存稳定 user_id 和必要显示属性,不复制密码、上游 token 或 MFA secret。
Refresh Token 仅保存不可逆 hash 和 generation。轮换、重放、解绑、logout、SCIM 与管理员撤销都通过稳定 family/session ID 操作。
| code | retryable | 用户文案/动作 |
|---|---|---|
identity_provider_unavailable | 是 | 登录服务暂时不可用,重试或选择其他已绑定方式 |
identity_provider_not_configured | 否 | 该企业尚未配置此登录方式,联系管理员 |
invalid_credentials | 否 | 邮箱或密码不正确;不指出哪一项存在 |
email_verification_required | 否 | 验证邮箱后继续 |
account_recovery_required | 否 | 配置恢复方式后继续高风险操作 |
identity_link_requires_reauthentication | 否 | 重新验证当前账号后绑定新方式 |
identity_already_linked | 否 | 该外部身份已属于另一个账号,不自动合并 |
last_login_method_cannot_be_removed | 否 | 先添加另一种登录或恢复方式 |
mfa_required | 否 | 完成当前要求的二次认证 |
step_up_required | 否 | 为本次高风险操作重新认证 |
session_expired | 否 | 重新登录;不宣称网络已断开 |
identity_deprovisioned | 否 | 企业身份已停用,联系管理员 |
device_code_disabled | 否 | 此 Network 不允许交互注册,使用 Enrollment Key 或联系管理员 |
identity_protocol_unsupported | 否 | 客户端或服务端版本不兼容,明确升级哪一端 |
错误 message 只用于展示,客户端必须按稳定 code 分支。读取失败不能表示成“账号不存在”,未知 Provider/claim/assurance 不能回落到更宽松认证。
必须审计:注册、登录成功/失败摘要、身份绑定/解绑、密码或 Passkey 变更、MFA/恢复方式变更、step-up、session/family 撤销、重放检测、SCIM deprovision、Federation Binding 变更和恢复管理员操作。
审计记录 actor、target user、Organization scope(如有)、binding/provider ID、结果、原因码、来源摘要、时间和 trace ID;不记录密码、authorization code、Access/Refresh Token、上游 token、TOTP seed、完整恢复码、Passkey 私钥或 Device 私钥。
跨 Organization 查询只返回本组织 Membership 和最小用户显示信息。某用户属于其他 Organization、绑定了哪些私人登录方式、个人空间里有哪些 Device,不向企业管理员披露。
必须执行的端到端旅程:
bootstrap-admin 完成首次初始化。