Skip to content
bitzorcas
中EN

Concept

用户代理与租户切入

区分同租户用户模拟登录与跨租户 Tenant Impersonation,说明直接签发、TabScoped/SiteWide 交接、逐请求撤销、敏感动作限制和审计边界。

Last updated

BitzOrcas 提供两条受控支持路径:用户模拟登录代表同租户用户处理业务;Tenant Impersonation 让平台操作员在已有授权下切入客户租户。两者都会保留真实操作者,但改变的安全上下文不同,不能混成一个“切换身份”按钮。

两条安全链路

同租户代表用户跨租户运维

已认证操作员

支持场景

Delegation grant + token

Tenant impersonation grant + token

Delegated caller:目标用户 + 真实代理人

目标 tenant + 操作员 + 原 tenant

逐请求撤销检查、授权、审计

普通用户身份、Delegated caller 和 Host operator 是不同调用方类型。业务代码应读取 ICurrentUser 与租户上下文,不从任意请求头或散落 Claim 自行推断代理状态。

场景与不变量

场景改变什么必须保留什么
用户模拟登录当前业务用户target、impersonator、租户、原因、会话代际、期限与 handoff 模式
Tenant Impersonation当前租户operator、原租户、目标租户、grant

签发服务拒绝嵌套代理,避免出现“甲代理乙后再代理丙”的不可审计链。用户模拟登录要求精确权限、同租户且非 Host 的目标、原因和 1–120 分钟时长;不存在记录时会创建 DelegationGrant,并不要求目标用户预先批准。Tenant Impersonation 则拒绝空目标和切入自身租户,并要求存在处于有效期内的跨租户 grant。

两类短期令牌的硬上限都是两小时。用户模拟登录按请求的 1–120 分钟签发;Tenant Impersonation 的期限还受已有 grant 剩余时间约束。

两类 grant 的建立方式不同

两条链路都把服务端 grant 视为可撤销的权威事实,把 token 视为短期投影;差别在于 grant 如何建立。

  • 用户模拟登录由具备 identity.user.impersonate 的管理员直接发起。服务在同一“管理员 + 目标用户”记录上创建或轮换会话代际,保存 Reason、SessionId、ExpiresAt 与 HandoffMode。
  • Tenant Impersonation 面向跨租户 Host 支持,必须先有覆盖 operator 与目标租户的有效授权记录。
受控发起/跨租户审批 → 服务端 grant + 会话代际 → 短期 token → 每请求复核 grant
│
└─ revoke/reissue/expire 立即失败

调用 JWT builder 不能绕过对应 Application Handler、精确权限、目标归属和权威记录。紧急 break-glass 仍应建立独立、高强度、短时且强审计的授权路径。

请求管线位置

API 先建立基本认证,再运行 Delegation middleware,随后解析 tenant guard,并在之后运行 Tenant Impersonation middleware。两种 middleware 都会检查令牌独立过期和授权现状。

Authentication
→ DelegationTokenMiddleware
→ TenantResolution / TenantGuard
→ TenantImpersonationTokenMiddleware
→ Audit / HTTP Authorization / Endpoints

Delegation middleware 当前把声明不完整或独立期限已到映射为 Delegation.Expired,把 grant 不存在、撤销、重签代际变化或权威查询失败映射为 Delegation.Revoked,均返回 401。Delegation.Unavailable 仍在 Host 错误目录中,但当前中间件路径不使用它。失败后不得以原调用者“静默降级”。

Delegation 的真实边界

Delegated token 把有效 caller 投影为 CallerType.Delegated,同时保留 impersonator、grant、session 与独立 expiry。授权决策缓存对 Delegated 调用者直接绕过,因为会话有自己的撤销和代际节奏;复用普通用户缓存可能让撤销失效。

// 业务用例只读取统一上下文,不直接解析 delegation claim。
var actor = currentUser.UserId;
var realOperator = currentUser.ImpersonatorId;
// 审计必须同时保留业务主体与真实操作者。
audit.Record(actorId: actor, impersonatorId: realOperator);

DelegationGrantStore 已改为消费 IEntitySet<DelegationGrant> 与统一 ICommandRepository,共享集成测试同时登记 SqlSugar 和 EF Core 泛型仓储。交付验证仍需覆盖两套 Provider 的唯一键、代际轮换、HandoffMode 列与事务语义;不能只凭 ImpersonatorId 字段存在就宣称完整 parity。

浏览器 handoff 支持 TabScoped 与 SiteWide。前者只让目标标签页采用短期 access;后者通过同源广播同步已打开标签页,并以不含 Token 的 SessionId 指针配合管理员 HttpOnly cookie 完成冷启动 resume。未配置租户策略时默认 TabScoped,请求可以显式覆盖。

Tenant Impersonation 的真实边界

Tenant Impersonation 用于平台支持和运维,而非客户侧角色切换。它保留 operator user id 和原 tenant,并把下游 tenant context 切换到目标租户。任何查询仍必须经过目标租户过滤与资源授权。

// 签发时拒绝空目标、自身租户、嵌套状态和无有效 grant。
var descriptor = await tokenService.IssueAsync(
@operator,
targetTenantId,
cancellationToken);
// 成功描述符的期限不会超过 grant 剩余时间或两小时上限。
return descriptor.ExpiresAt;

切入目标租户不自动授予该租户管理员权限。授权层仍要根据专用支持权限、动作限制与资源属性决策;Feature entitlement 与 DataScope 也不能被跳过。

高风险动作

代理期间建议禁止或追加 step-up 的操作包括:修改认证因子、创建/导出密钥、变更角色权限、删除租户、发起付款、批量导出 PII 和更改审计保留策略。

限制应落实在授权策略或 Handler precondition,而不只是在 UI 隐藏按钮。API 客户端、后台命令和旧前端都可能绕过展示层。

public static class DelegationErrors
{
public static readonly Error ForbiddenAction =
Error.Forbidden(
"Security.Delegation.ForbiddenAction",
"This action cannot run in a delegated session.");
}
// 对不可代理动作明确拒绝,避免依赖前端隐藏。
if (currentUser.CallerType == CallerType.Delegated)
return Result.Failure(DelegationErrors.ForbiddenAction);

用户体验

进入代理状态前显示目标身份、租户、理由、到期时间与 handoff 模式;进入后使用持续可见的横幅,并提供立即退出。TabScoped 要明确哪些标签页仍是管理员,SiteWide 要同步采用与退出,并在失败时撤销服务端会话。

退出不能只清除本地 token。/exit 撤销当前 JWT 的精确代际,真实管理员 DELETE 可幂等撤销目标会话,/restore 再用 HttpOnly refresh cookie 恢复管理员身份。客户可见的支持记录应遵守隐私与安全披露策略。

审计证据

每次签发、使用、拒绝、退出、过期和撤销都应关联:

  • 原始操作员、业务主体、原租户与目标租户;
  • grant/token 标识、理由、工单与审批人;
  • action/resource、结果、时间和客户端上下文;
  • CorrelationId、TraceId 与受影响聚合;
  • 高风险动作的额外审批或拒绝原因。

日志和审计不能保存代理 token 明文。查询界面应能按操作员、客户租户、时间段和工单重建完整会话。

测试矩阵

  1. 用户模拟登录覆盖无旧记录自动创建、重签代际、空目标、自己、Host 与跨租户拒绝;
  2. 时长只接受 1–120 分钟;Tenant Impersonation 仍受跨租户 grant 剩余期限约束;
  3. Delegation 与 Tenant Impersonation 均拒绝嵌套;
  4. 撤销后下一请求失败,且不回退原身份继续执行;
  5. 授权缓存不会延长 delegated session;
  6. 目标租户查询仍受 tenant filter 与 DataScope 限制;
  7. 审计同时保存 actor 与 impersonator;
  8. TabScoped 不可 resume,SiteWide 的 cookie/Origin/平台/SessionId 均需校验;
  9. 各 persistence profile 的支持/拒绝行为都有 Consumer Contract Test。

当前差距与采用建议

当前主线已具备两类 token service、middleware、用户模拟登录发起/当前状态/退出/撤销/恢复端点、双 handoff 模式、租户策略、敏感命令统一拒绝和审计承载。Provider 采用仍不能只验证登录后 Claim;必须把 grant 保存、代际轮换、逐请求撤销、handoff schema 迁移和审计查询纳入合同测试。

前端启用双模式前必须先应用 202608090007-impersonation-handoff-mode.sql。当前源码工作树还为 SqlSugar CodeFirst 非空列补了 DEFAULT 'TabScoped';发布时应把这项未提交改动与文档所依据的源码修订一起纳入评审。

相关主题

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%