NSIO Docs
NSIO Docs
首页

NSIO Next · 当前开发基线

统一 L3 + L4 架构
产品能力目录与实现闭环
功能闭环总账
产品闭环与功能实现
实施蓝图与交付契约
发行、升级与卸载
跨组件共享契约
控制资源生命周期
控制投影与 Runtime Protocol
数据面协议
Grant 与策略编译

组件实现规格

ns · 统一节点运行时
Client · App、CLI 与门户
NSD · 身份与控制面
NSGW · 增值数据面
身份、登录与会话
注册、准入与配额协议
商业模型与 Entitlement
采购、计费与发票
服务运营与 SLA
备份与灾难恢复
信任、合规与数据权利

Last Updated: 2026/8/8 22:11:23

Previous PageNSGW · 增值数据面
Next Page注册、准入与配额协议

#NSIO Next · 身份、登录与会话实现基线

状态:产品与协议实现依据。本文定义人类身份、登录入口、账号绑定、会话、MFA、身份撤销和 App/CLI 回调。设备能否加入 Network 仍由注册、准入与配额协议决定;登录成功本身不创建 Device、Node Membership 或访问 Grant。

#0. 已定结论

  1. 不复制 Tailscale 的身份产品。 NSIO Next 使用标准 OIDC 作为组件边界,但同时提供本地邮箱密码,不要求所有人先拥有第三方 IdP。
  2. 邮箱不是统一登录前置。 邮箱密码才要求邮箱;Google 和 GitHub 可直接进入各自流程;企业 SSO 只在需要发现企业 IdP 时再询问企业邮箱或组织域名。
  3. App 不处理密码。 桌面和移动 App 只打开系统浏览器,浏览器完成认证后通过 Authorization Code + PKCE 返回 App。
  4. 首版登录方式:邮箱密码、Google、GitHub,以及企业配置的 OIDC。Passkey、微信、企业微信、飞书、钉钉、Microsoft、Apple 等后续以 Connector 增加,不改变 User、Device、Enrollment 或 Grant 模型。
  5. 不建立地区专属身份分支。 页面按部署配置和 Provider 可用性展示入口,不根据 IP、语言或地区切换安全模型。
  6. Identity Authority 是逻辑角色。 云服务可由 NSIO 托管;私有部署可使用内置身份服务或客户 OIDC。NSD、App 和 CLI 只依赖标准协议,不依赖某个 IdP 产品名。
  7. 人、设备、网络授权分离。 身份会话证明“谁在操作”;Device Key 证明“是哪台设备”;Enrollment Policy 决定“能否加入”;Grant 决定“加入后能访问什么”。
  8. Next 从零开始。 不兼容旧 NSIO 用户、邮箱匹配、Auth Key、Device Code 或会话格式;可复用代码必须按本文契约重新验收。

#1. 角色与权威边界

角色权威事实明确不负责
Identity Authority账号、登录方式、凭据、MFA、认证强度、用户会话Network 准入、设备身份、数据面授权
NSDOrganization、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 或解绑登录方式不能代替删除。

#2. 登录页与用户交互

#2.1 云托管登录页

首屏直接展示可用方式,不先要求所有用户输入邮箱:

登录 NSIO

邮箱
[ clark@example.com                         ]

密码
[ •••••••••••                               ]

[ 登录 ]

[ 忘记密码 ]                         [ 注册账号 ]

-------------------- 或 --------------------

[ 使用 Google 登录 ]
[ 使用 GitHub 登录 ]
[ 使用企业 SSO ]

交互硬规则:

  • Google 和 GitHub 不读取或要求上方邮箱字段;
  • “使用企业 SSO”被点击后,才要求企业邮箱或组织域名用于 Home Realm Discovery;
  • 登录入口只展示当前部署真实配置的 Provider;已配置但健康检查失败的入口保持可见并禁用,显示“暂时不可用”和重试,不能伪装成该方式不存在;
  • 注册、登录和找回密码分别是明确动作,不用“继续”同时猜测用户意图;
  • 登录失败不透露邮箱是否存在。已知账号需要引导正确登录方式时,只能在完成邮箱所有权证明或受信邀请上下文后展示;
  • 页面脚本、字体、验证码和静态资源不能强依赖某个地区不可达的第三方域名。

#2.2 私有部署登录页

  • 页面标题、域名和 Provider 使用客户部署配置;
  • 可只启用本地邮箱密码,也可只启用企业 OIDC,或同时启用;
  • 私有部署的 Google/GitHub 需要客户自己的 OAuth 应用与精确 Redirect URI,不复用 NSIO Cloud 的 client secret;
  • 无 SMTP 时,首个管理员通过 bootstrap-admin 创建并登录,再配置 SMTP 或企业 OIDC;
  • 隔离环境不显示无法使用的互联网 Provider,不保留灰色诱饵按钮。

#2.3 企业 SSO

  1. 用户点击“使用企业 SSO”;
  2. 输入企业邮箱或组织域名;
  3. Identity Authority 只返回可操作结果:“继续使用企业账号”“未配置企业登录”或可重试故障,不公开 Organization、成员或 Network 目录;
  4. 浏览器跳转企业 OIDC;
  5. 回调校验 state、nonce、PKCE、iss、aud、exp,再根据 (issuer, subject) 定位身份;
  6. 登录后才显示该主体可接受的邀请和可进入目标。

NSIO Next 对外只定义 OIDC。客户仍可在自己的 Identity Authority 后连接 SAML、LDAP 或其他目录,但这些上游协议不进入 App、NSD 业务 API 或 Enrollment 契约。

#2.4 首次注册与个人空间

登录方式不同,但首次创建账号必须落到同一条事务:

  • 邮箱密码:用户明确点击“注册账号”,提交邮箱和密码,完成邮箱验证后创建 User 与本地 identity binding;登录按钮不能因邮箱未知而静默变成注册;
  • Google/GitHub:完成 Provider 认证后,以 (issuer, subject) 查找。未知且已验证邮箱未占用时创建 User 与 binding;邮箱已属于其他账号时不自动合并,引导先登录原账号再绑定;Provider 没有可信 verified email 时要求补做邮箱验证;
  • Passkey(后续):作为独立 Connector 与凭据绑定流程增加,不要求在首屏预填邮箱;首版 WebAuthn 只承担已登录账号的 MFA/step-up,不作为首要注册方式;
  • 企业 OIDC:是否允许自动创建账号由 Federation Binding 决定。invited_only 只接受邀请/SCIM 已存在主体,jit 可在已验证域和映射规则内创建 Organization User;
  • 邀请:邀请只限定可接受主体和 Organization/Network,不替代身份认证,也不允许把邀请转给另一 (issuer, subject)。

Identity User 成功创建后,NSD 才原子创建其 Personal Organization、默认 Network、个人模板和 Organization Membership。任何 Provider 回调失败、邮箱验证失败或重复 binding 冲突都不得留下半个个人空间。Device 与 Node Membership 仍要随后通过 Enrollment Grant commit 创建。

#3. App 与 CLI 登录闭环

#3.1 桌面 App

点击“登录并连接”
  -> App 生成 PKCE verifier/challenge 和一次性 state
  -> 打开系统浏览器
  -> 用户在登录页选择邮箱密码、Google、GitHub 或企业 SSO
  -> Identity Authority 回调 loopback URI
  -> App 以 authorization code + verifier 换取会话
  -> 会话与 Staging Device Key 共同完成 Enrollment Proof
  -> Policy/审批/Grant commit
  -> 申请 TUN 权限并连接
  • App 内不嵌登录 WebView,不接收密码,不读取 Provider Cookie;
  • loopback listener 只绑定本机,使用随机端口、单次 state 和短 TTL;
  • 浏览器认证成功但 App 回调失败时,页面提供“返回 App”和可复制的诊断 ID,不展示 authorization code;
  • 已有有效会话且策略未要求重新认证时,新建同一 Organization 的 Enrollment Request 不重复打开浏览器;仍必须由会话和当前 Staging Device Key 共同签名;
  • 跨 Organization 注册使用新的 Device Key。策略可以要求重新认证或 step-up。

#3.2 iOS / Android

移动端使用系统认证会话和 Universal Link/App Link 回调。回调 URI 必须与包签名、域名关联文件和 PKCE state 同时成立;自定义 scheme 只能作为明确记录风险的兼容回退,不能成为首选。

#3.3 有浏览器 CLI

ns up 默认打开系统浏览器,流程与桌面 App 相同。CLI 监听 loopback 回调并显示明确状态,不把完整 token 打印到终端或 shell history。

#3.4 无头 CLI

ns up --headless 使用 Device Code:

$ ns up --headless
Open https://login.ns.io/device and enter ABCD-EFGH
Confirm phrase: BLUE RIVER
Waiting for confirmation...

用户在另一台设备登录后看到设备名、OS、短公钥指纹、校验短语、Organization、Network 和请求能力,再选择“确认这是我的设备”或“这不是我发起的”。Device Code 适合有人操作的无头设备,不用于无人值守生产服务器。

#3.5 无人值守节点

服务器、路由器、容器、CI 和自动扩缩容使用受限 Enrollment Key 或 Workload Attestation,不创建人类浏览器会话。生产 Network 可以配置:

interactive_enrollment = allowed | approval_required | disabled
allowed_ownership      = user | organization | both

推荐生产/服务器 Network 默认 interactive_enrollment=disabled、allowed_ownership=organization。这防止运维人员因为 Device Code 更方便而把生产节点错误注册为个人资产。

#4. 账号与身份模型

#4.1 稳定主键

外部身份唯一键是:

(issuer, subject)

邮箱、用户名、头像和显示名都是可变属性,不是授权主键。企业 OIDC、Google、GitHub 和未来微信 Connector 都必须产生稳定 issuer + subject;更换邮箱不创建新 User,也不悄悄转移身份。

本地邮箱密码账号由 Identity Authority 自己作为 issuer,并给账号分配不可变 subject。密码使用可升级参数的 Argon2id;服务端不记录可逆密码,不在日志或审计中保存凭据、验证码或重置 token。

#4.2 邮箱唯一性与账号绑定

  • 一个 Identity Authority 内,一个已验证邮箱只能属于一个账号;
  • 邮箱相同不能自动绑定外部身份;
  • 添加 Google、GitHub、后续 Passkey 或企业身份时,用户必须先登录现有账号并完成当前方式重新认证,再证明新方式;
  • 绑定操作展示新增 issuer、显示标识和影响,写安全审计;
  • 已存在邮箱通过另一入口出现时,引导用户登录原账号后绑定,不创建两个不可分辨账号,也不自动接管;
  • 删除最后一种可用登录/恢复方式前必须先添加替代方式;最后一个恢复管理员不能自行删除唯一恢复能力。

#4.3 登录方式解绑

用户解绑某个身份来源时:

  1. 要求当前账号重新认证或 step-up;
  2. 撤销由该 identity_binding_id 建立的浏览器会话和 Refresh Token Family;
  3. 其他登录方式建立的会话不受影响;
  4. Organization Membership、Device 和数据面 Grant 不因普通解绑自动撤销;
  5. 若企业 Policy 要求该身份来源,解绑被拒绝并指出管理员策略。

#5. 会话、MFA 与 Step-up

#5.1 会话

  • Access Token 短期有效;Refresh Token 使用一次即轮换;
  • 旧 Refresh Token 被再次使用时,撤销整个 token family,记录重放安全事件;
  • 浏览器会话、App 会话和 CLI 会话具有独立 audience,不能互换;
  • Token 绑定 Identity Authority、User、client、会话族和认证时间;
  • 会话过期默认只影响控制台、配置、发布服务和管理 API,不让已经有效的 Device Membership 或隧道突然断开。

企业可以显式启用 continuous_identity_required,把身份重新验证与 Membership 续租绑定。该策略默认关闭;启用前必须显示离线设备和 IdP 故障对网络可用性的影响。

#5.2 MFA 与认证强度

本地身份首版支持 TOTP、恢复码和 WebAuthn 二次因子;Passkey 主登录后续开放。企业 OIDC 的认证强度由受信 Federation Binding 映射 amr、acr 和 auth_time:

  • IdP 已证明达到目标 assurance 时,不重复要求 NSIO TOTP;
  • claim 缺失、过旧或强度不足时,Identity Authority 执行本地 step-up;
  • 不能仅凭“来自企业 SSO”假设已完成 MFA;
  • Federation Binding 明确哪些 acr/amr 可满足哪些 NSIO assurance,默认不信任未知值。

#5.3 高风险操作

修改 Owner、Federation Binding、SCIM、恢复方式、Enrollment Policy、跨组织 Share、公共入口或破坏性撤销前,需要新鲜 step-up。每次 challenge 绑定具体操作、资源、请求 digest 和短 TTL,不能把一次登录 MFA 无限期复用为所有高风险操作的授权。

#6. 身份生命周期与撤销

不同事件不能压成一个“用户失效”布尔:

事件会话/TokenOrganization MembershipDevice数据面
用户普通退出登录撤销当前会话或所选设备会话不变不变默认不变
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 明确撤销撤销该设备控制会话撤销其全部 MembershipDevice 进入 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 到期后要求用户再次完成上游登录;这限制新的控制面会话,不默认切断已建立的数据面。

#7. 账号恢复

恢复方式是统一账号安全能力,不按地区分叉:

  • 邮箱重置链接;
  • Passkey/WebAuthn;
  • TOTP 恢复码;
  • 受控的恢复管理员流程;
  • 私有部署 bootstrap-admin 紧急初始化,仅用于不存在可用管理员的安装阶段。

注册完成后必须强引导用户配置至少一种不依赖当前登录方式的恢复能力;用户可以稍后完成普通配置,但 Owner/唯一管理员在未设置恢复方式前不能关闭安全提醒。恢复操作必须撤销既有 Refresh Token Family、记录操作者和恢复渠道,并通知其他已验证渠道。

管理员不能查看用户密码、Passkey 私钥、TOTP seed 或完整恢复码。一次性重置链接只允许设置新凭据,不回显旧凭据。

#8. 部署与 Connector 扩展

#8.1 首版能力

部署邮箱密码GoogleGitHubPasskey 主登录企业 OIDC
NSIO Cloud是是是后续按 Organization 配置
私有部署可选客户自配 OAuth App客户自配 OAuth App后续是
隔离部署是否否后续内网 OIDC 可选

#8.2 后续 Connector

微信、企业微信、飞书、钉钉、Microsoft、Apple 等通过 Identity Authority Connector 接入。每个 Connector 必须提供稳定 issuer/subject、明确 claim 映射、回调域名、密钥轮换、禁用状态和审计来源;不得把 Provider 特有字段直接写入 ACL 或 Device 表。

新增 Connector 是增加登录方式,不是新增 Enrollment Proof 状态、User 类型或 ACL 主体类型。Provider 暂时不可达时返回可重试错误,不回落到按邮箱自动匹配。

#9. 权威数据结构

#9.1 身份表

identity_users(
  user_id, status, primary_verified_email?, created_at, revision
)

identity_bindings(
  binding_id, user_id, issuer, subject, provider_kind,
  email?, email_verified, status, created_at, last_authenticated_at,
  UNIQUE(issuer, subject)
)

local_credentials(
  credential_id, user_id, password_hash?, password_params?,
  disabled_at?, updated_at
)

webauthn_credentials(
  credential_id, user_id, public_key, sign_count,
  transports, created_at, last_used_at, revoked_at?
)

凭据表与 NSD Organization User/Membership 表分离。NSD 只保存稳定 user_id 和必要显示属性,不复制密码、上游 token 或 MFA secret。

#9.2 会话表

identity_sessions(
  session_id, user_id, binding_id, client_id, audience,
  auth_time, assurance_level, expires_at, revoked_at?
)

refresh_token_families(
  family_id, session_id, current_generation,
  expires_at, replay_detected_at?, revoked_at?
)

Refresh Token 仅保存不可逆 hash 和 generation。轮换、重放、解绑、logout、SCIM 与管理员撤销都通过稳定 family/session ID 操作。

#10. 稳定错误与用户动作

coderetryable用户文案/动作
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 不能回落到更宽松认证。

#11. 审计与隐私

必须审计:注册、登录成功/失败摘要、身份绑定/解绑、密码或 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,不向企业管理员披露。

#12. 实施顺序与验收

  1. 定义 Identity Authority OIDC、User/Binding/Session schema 和稳定错误码;
  2. 完成本地邮箱密码、Google、GitHub 和企业 OIDC Connector;WebAuthn 先用于 MFA/step-up;
  3. 完成系统浏览器 + PKCE 的桌面、移动和 CLI 回调;
  4. 把 Identity session + Device Key 接入 Enrollment Proof,不复用旧 Auth Key/Device Code;
  5. 完成 MFA assurance 映射、按操作 step-up、绑定/解绑和恢复;
  6. 完成 logout、SCIM、离职、Device 撤销的分类事务和 5 分钟 SLA;
  7. 最后增加更多 Connector,不为 Provider 增加业务模型分支。

必须执行的端到端旅程:

  • 新用户分别用邮箱密码、Google 和 GitHub 登录,自动创建个人空间并注册首台设备;
  • Google/GitHub 登录不填写邮箱字段;企业 SSO 只有点击后才询问企业邮箱/域名;
  • 同一邮箱试图从另一 Provider 登录时不自动合并,登录原账号后可安全绑定;
  • App 不出现密码输入,浏览器完成 PKCE 后正确回到 App;
  • 无头 CLI 通过另一台设备确认,生产 Network 禁用 Device Code 后返回准确错误;
  • 普通 logout、身份解绑、SCIM 离职和 Device 撤销分别产生不同结果;
  • SCIM 离职后组织资产 Device 保留,用户 Membership/Grant 在 SLA 内收敛;
  • 控制会话过期不让默认数据面突然断开;显式连续身份策略启用时按策略收敛;
  • Provider、存储或 SMTP 故障显示可重试故障,不伪装成账号不存在或空组织;
  • 私有部署无 SMTP 时可用 bootstrap-admin 完成首次初始化。