通用多租户自定义角色权限模型

前段时间在忙一个saas系统的设计,这里总结一下经验。

首先是用户付费方式一般以模块的形式进行,如果saas系统各租户的需求在细节上有很多不同,那就要对模块进行一些微调,在代码上使用策略模式进行归类区分抽象。但是总的来说,系统大的功能点应该相差不大,否则就属于定制化开发的范畴了。

权限系统可以抽象为以下部分:

  1. 功能点。功能点是一个全集,与后台的API对应。不同用户能够看到的功能点是不一样的,这取决于购买的需求;
  2. UI。功能点对应的UI可以由很多套,不同平台的客户端,不同版本的移动端,都可能有不同的UI;功能点分别关联到UI和API;
  3. 角色。各租户除了内置的管理员,其他角色可以由用户自己定义;注意:并不是所有的saas系统都有这种需求,统一设计角色的话,系统设计会精简很多;
  4. 权限。角色在定义的时候关联了功能点的权限。

详细解释如下——

功能点

系统按着模块拆分功能点,功能点是最细的权限粒度。保证UI和API相对功能点都是一对多的关系,不存在多对多的关系。

如果感觉用户操作功能点分配权限过于繁琐,可以对功能点做一个功能集,这样分配的粒度就会比较粗,但是也可以随时细化。

功能点都有一个对应的权限描述方式,可以采用二进制位运算表示,也可以用权限字符串(参考shiro)。如果权限的判定需要根据用户请求的参数来决定,那就要动态的权限字符串(参考spel)。我这里用了spel的方式来描述权限,可以用Spring security来实现,或者自己用Spring AOP写一个权限描述。最后的形式类似于#prj:device:view,表示某个project的设备查看。

每个API都有自己的权限需求,这与功能点的权限描述字符串对应。这里也是一对多的关系,API可以要求多个权限。用户必须拥有全部权限才能访问API。

功能点理论上也是树型的,不过某些功能点可能对其他功能点有额外的依赖。

UI

UI分为两部分,一个是匹配规则,一个是UI树本身。

这个比较简单,就是为不同版本、产品,甚至租户设置不同的UI,根据客户端的情况和用户的功能点权限返回UI树给用户渲染。

UI树不一定需要在服务器存一套完整的,需要权限控制的部分才需要存入数据库。

角色

简单起见,只有租户的管理员才可以给组织建立对应的角色树。

角色树关联功能点,某些功能点可能和具体的数据有关,需要额外选择。

数据权限

指的是不同人看到的字段都不一样,或者字段的渲染不一样。

这个比较麻烦,不太好做成通用的。非要做的话,每个API返回的字段都要存到表里,然后在功能点那一层,最后关联到字段。即#prj:device:view:field,但是这样太过繁琐,对执行效率影响很大。如果没有很通用的需求,可以在代码里对一些特殊API做单独的处理。