建一个 tenant 表用于权限控制,和 user 表是 one2many 的关系,每个级别的用户都有一个对 tenant 。tenant 表内,每个 tenant 和下属级别 tenant 又是一对多的关系(加一个字段 parent_id, 因为是同一个类型,所以是构成的拓扑结构是树状的,参考
https://entgo.io/docs/schema-edges/#o2m-same-type )。省级的 tenant 是 root,没有 parent,但可以添加市级的 children,市级的 tenant 又可以添加区县级的 children,如此一来构成一棵树,还能方便地查询出任一个 tenant 的 children 。添加 children 通过为下属 tenant 设置 parent_id 到上级区域的 tenant id 来完成。
User 创建的数据都可以和 tenant 联系起来。比如通过一个省级的用户,查到他的 tenant,再通过这个 tenant id 查到下属 tenant,进而可以查到这些 tenants 对应的 users,以及属于这些 users 的数据。当然,这是最简单的情形,省级用户可以看到所有市级和区县级用户的数据,如果还要求省级用户只看到部分授权的市级用户的数据,可以在 tenant 表再建一个 tenant 到 tenant 的一对多关系(加一个字段 managed_by_id ),这时候添加授权也是表现为对一个 tenant 添加 children,具体的数据库操作表现为为下属区域 tenant (被授权查看)设置 managed_by_id 到上级 tenant id 。不过添加 children 之前还需要验证下属被管理的 tenant 是否已经指向了上级管理 tenant 的 id,如果没有,说明这不是一个合规操作。
如果要查询一个上级 tenant 的所有下属的数据,就通过 parent_id 来遍历树。如果要查询一个上级 tenant 的已授权的的下属的数据,通过 managed_by_id 来遍历树。
Go 的 ORM Ent. 内建这种 policy 支持,可以作为参考:
https://entgo.io/docs/privacy/