从目前AI工程化的角度来看,多租户系统越来越重要,传统 RBAC(基于角色的访问控制)通常依赖树形组织结构。 我在实践中尝试了一种新思路:链表为主体,跳表加速,哈希表直达,再辅以 SessionID 管理会话安全与状态。 这篇博客是我前段时间思考的一种多租户权限管理设计思路,顺便把它整理出来总结一下。 以链表为基础,结合跳表和哈希表实现用户节点的快速增删与查询,在保证多租户隔离的前提下,提供极高的灵活性和可扩展性。
核心设计思想
链表(Linked List)
每个用户是主链表的一个节点;当用户创建团队时,在其下挂载团队子链表。链表插入/删除近 O(1)。
跳表(Skip List)
为有序遍历、范围检索、分页提供 O(log n) 查询/插入。
哈希表(Hash Map)
uid → UserNode、team_id → TeamNode。
SessionID
强绑定 uid 的会话实例,用于登录态与设备级控制;缓存中维护 session_id → uid,支持强制下线、多设备策略。
RBAC + ABAC
角色聚合(直绑/团队继承/租户默认)与属性策略(时间/地点/设备/标签)结合,由 PDP(策略决策点)裁决。
Outbox 事件一致性
数据库为真,事件驱动索引/缓存同步,避免脏读与丢失更新。
–
总体系统架构
1. 数据结构架构图
1.1 ER模型(ER持久层)
1.2 类图
1.3 运行时数据结构(链表 + 子链表 + 跳表 + 哈希表)
2. SessionID: 与uid的强绑定与会话安全
核心关系:一个 uid 可拥有多个 session_id(多设备/多终端并行登录);每个 session_id 都是该用户一次独立会话。
2.1 会话与缓存命名空间
说明:
多设备:若需“单设备登录”,新登录时清空 user:sess:{uid} 下旧会话并删除对应 sess:*。
续期:短 session_id TTL + 长 refresh_token;续期时延长 Redis TTL 与 sessions.expires_at。
强制下线:删除 user:sess:{uid} 集合中所有 session_id,并清理 sess:*。
Cookie/Token安全:Cookie 走 Secure + HttpOnly + SameSite=Lax/Strict;Header 走 Authorization: Bearer 时注意 CSRF 防护。
设备画像:device_info(平台/机型/指纹)+ ip/ua 辅助风控、异常会话识别。
3. 权限裁决(PDP):RBAC + ABAC
3.1 裁决流程
要点:
- Deny 优先:任何冲突以拒绝为先,避免权限提升。
- 合并策略:用户直绑(user→role);团队继承(team→role;用户 ∈ 团队):租户默认角色(tenant baseline)
- ABAC 条件:时间窗、IP/地理、设备指纹、资源所有者、业务标签等;条件放在 condition_json 中。
- 决策缓存:perm:dec:* 短 TTL + 变更事件精准失效(按 role_id、uid 打 tag)。
4. 核心业务流程
4.1 登录/续期/登出
4.2 受保护API的访问(权限校验)
4.3 数据写入与一致性(Outbox驱动)
5. 复杂度说明
6. 失效策略与降级路径
决策缓存失效
基于事件的精准失效(role-change、binding-change、user-disable)而非单纯 TTL。
缓存穿透
对不存在 uid 做短 TTL 空值缓存。
雪崩
TTL 抖动 + 热点 Key 预热 + singleflight 合并回源。
回源风暴
速率限制 + 局部降级(只读路径、停用某些 ABAC 条件)。
强一致与最终一致
写路径强一致(事务),读路径最终一致(缓存/索引同步可延迟毫秒—秒级)。
7. 安全要点与合规
最小权限原则(PoLP)
默认仅基线角色;临时权限带 TTL。
Deny 优先
冲突策略优先拒绝。
会话安全
session_id 仅服务端可验证;Cookie 场景启用 HttpOnly/Secure/SameSite。
审计
会话、角色变更、敏感资源访问全量审计,留存期与合规匹配(如 SOC2、ISO27001)。
设备/环境约束
(ABAC):地理围栏、IP 白名单、设备指纹、工作时间窗。
多租户隔离
数据、缓存、日志都显式带 tenant_id;避免“串租”。
以上是我思考的架构设计,利用GPT5帮我润色了一下,根据这个架构我构建了一个单机的多租户系统,至于分布式的系统可能这个架构也有局限性吧,不过目前够用就行,后续上升到分布式再考虑进一步优化。