3. 统一身份数据模型

在医疗SaaS中,身份数据模型不是简单的“用户表+角色表”,而是承载租户隔离、组织层级、岗位职责、权限边界与审计追溯的核心骨架。医疗场景的特殊性在于:同一套系统服务多家医院、连锁诊所或区域医联体,每家机构都有独立的组织架构、科室编制、人员执业范围和数据访问边界;同时,医生可能多点执业、护士可能轮转科室、管理员可能跨院区授权。因此,模型必须同时回答三个问题:谁在哪个租户下、属于哪个组织节点、能对哪些资源做什么操作。

一、五个核心实体的职责边界

统一身份模型通常围绕五个实体展开:租户(Tenant)、组织(Org)、用户(User)、角色(Role)、权限(Permission)。它们不是平铺的,而是有明确的归属与引用关系。

  • 租户是最高级别的隔离单元,代表一家独立签约的医疗机构或医疗集团。租户拥有自己的组织树、用户池、角色集和数据空间。租户之间默认不可见、不可跨访。
  • 组织是租户内部的层级结构,通常表现为“院区→科室→病区/班组”的树。组织节点既是人员归属的容器,也是数据权限的天然边界,例如科室主任只能查看本科室数据。
  • 用户是自然人账号,承载登录凭证、身份标识和联系方式。一个用户在同一租户内通常只有一个账号,但可被分配到多个组织节点,承担不同岗位。
  • 角色是权限的集合,代表一类岗位职责,如“门诊医生”“病区护士长”“医保审核员”“租户管理员”。角色是用户与权限之间的桥梁,避免逐人授权。
  • 权限是最小操作单元,通常以“资源:动作”表达,如 patient:read、order:create、report:sign。权限可绑定到角色,也可在特殊情况下直接授予用户。

二、实体关系与关键约束

从关系上看:租户与组织是一对多,组织自关联形成树;租户与用户是一对多;用户与组织是多对多,通过“用户-组织任职”关联表表达,并记录岗位、是否主属组织、生效时间;角色与权限是多对多;用户与角色也是多对多,但必须限定在租户范围内,即“用户-角色”关联要带 tenant_id,防止跨租户角色串用。

一个容易被忽视的约束是:角色必须属于某个租户。系统可以预置“平台级角色模板”,但一旦分配给具体租户,就应实例化为该租户的角色,允许租户管理员在模板基础上裁剪权限。这样既保证开箱即用,又保留租户自治空间。

另一个关键点是组织与数据权限的联动。用户被分配到某组织节点后,其数据可见范围通常按“本节点+子节点”计算。例如,用户任职在“内科”节点,则默认可见内科及其下属病区数据;若需要跨科室协作,则通过额外的“数据授权”或“共享关系”表达,而不是把用户直接挂到根节点。

租户 Tenant tenant_id · 隔离边界 组织 Org(院区) org_id · parent_id 科室(内科) org_id · parent_id 病区 / 班组 org_id · parent_id 1:N 自关联 用户 User user_id · 登录凭证 · 自然人 角色 Role role_id · tenant_id · 岗位职责 权限 Permission resource:action · 最小操作单元 用户-组织任职 user_id · org_id · 岗位 · 主属 · 有效期 用户-角色分配 user_id · role_id · tenant_id 角色-权限绑定 role_id · permission_id 1:N 归属 N:M 任职 N:M 分配 N:M 绑定 N:M 关联 关联 关联 图例 租户内实体 多对多关联表(带租户约束) 所有关系均限定在同一 tenant_id 内

三、建模方法:从表结构到授权计算

落地时,建议采用“主数据表+关联表”的经典结构。核心表包括:tenant、org、user、role、permission,以及三张关联表:user_org、user_role、role_permission。所有业务表都应带 tenant_id,所有关联表也应带 tenant_id,并在数据库层建立联合唯一索引,例如 user_role 上建立 (tenant_id, user_id, role_id) 唯一约束,防止重复授权。

授权计算通常分两步:先算角色权限并集,再叠加组织数据范围。假设用户U在租户T下拥有角色R1和R2,R1包含 patient:read、order:create,R2包含 patient:read、report:sign,则功能权限并集为 {patient:read, order:create, report:sign}。随后,根据U在 user_org 中的任职节点,计算数据可见范围。若U任职于“内科”节点且为主属组织,则默认数据范围为“内科及其子节点”;若U同时兼任“急诊科”节点,则范围为两棵子树的并集。

对于跨租户场景,例如医生在A医院和B医院多点执业,应建立两个独立用户账号,分别归属不同租户,而不是用一个账号跨租户授权。这样既符合数据隔离要求,也便于审计时区分“在哪个机构、以什么身份、做了什么操作”。

建模检查清单:
  • 每张业务表是否都带 tenant_id,且查询条件默认注入?
  • user_role 是否带 tenant_id,防止跨租户角色串用?
  • 组织树是否支持无限层级,且查询子树时使用递归或闭包表?
  • 角色是否区分“模板角色”与“租户实例角色”?
  • 权限命名是否统一为 resource:action,避免同义异名?
  • 用户离职或转岗时,user_org 和 user_role 是否有失效时间字段?

四、常见建模陷阱与规避

第一个陷阱是把组织节点直接当角色用。例如“内科医生”既表示组织归属,又表示权限集合。一旦医生轮转到其他科室,权限无法平滑迁移。正确做法是组织归组织、角色归角色,两者通过用户关联表组合。

第二个陷阱是权限粒度过粗。如果只设“病历管理”一个权限,就无法区分“查看”“编辑”“签名”“归档”。医疗场景对签名、修改、导出尤其敏感,建议至少拆到动作级,并对高风险动作单独授权。

第三个陷阱是忽略有效期。医疗人员进修、轮转、临时支援非常普遍,授权应支持起止时间。查询时以当前时间过滤,过期授权自动失效,避免人工回收遗漏。

综上,统一身份数据模型的核心不是表越多越好,而是让租户、组织、用户、角色、权限五者各司其职、关系清晰、约束到位。模型一旦稳定,后续的认证、鉴权、审计、租户治理才有可靠的地基。