前面我们实现了一个前后端联动的基本流程,后端提供了一个API路由,前端提供了一个页面组件。本章节,我们准备添加一个菜单,并给菜单赋予相应的权限。当某个具备权限的用户进入系统,可以在首页看到此菜单

功能与菜单

CabloyJS是前后端分离的框架。前后端分离对后端路由的权限控制提出了更高的要求。因此,权限的核心就是对后端API路由的权限控制

功能API路由的关系

API路由的目的是向前端提供相应的API服务,在这里我们称之为功能。于是,一个或多个API路由对应一个功能

在实际操作中,是针对功能授权,然后在API路由中指定此路由对应哪个功能,从而实现对API路由的访问控制

功能菜单的关系

菜单属于功能的特例:

  1. 首先,菜单也对应一个或多个API路由,其授权方式与功能一致

  2. 其次,将功能的属性menu设为1,就成为了菜单,同时再给菜单指定一个前端页面组件的路径,就可以在首页显示一个菜单链接了

声明菜单

每个业务模块有一个meta元数据对象,我们可以在里面声明一个菜单

src/module/test-party/backend/src/meta.js

const meta = {
  base: {
    functions: {
      kitchenSink: {
        title: 'Kitchen-sink',
        scene: 'tools',
        actionPath: 'kitchen-sink/index',
        sorting: 1,
        menu: 1,
      },
    },
  },
};
名称 说明
title 菜单标题,如果要支持国际化,可以直接添加对应的语言资源
scene 菜单场景,用于菜单的分类显示
actionPath 前端页面组件路径
sorting 用于显示的排序值
menu 是否为菜单,如果不是菜单就是功能

绑定API路由

src/module/test-party/backend/src/routes.js

{ method: 'post', path: 'kitchen-sink/guide/echo9', controller: testKitchensinkGuide,
  meta: {
    right: {
      type: 'function',
      name: 'kitchenSink',
    },
  },
},
名称 说明
meta 是路由的元数据,可以指定与中间件相关的参数
right 中间件right的参数
type 授权类型,这里是功能授权
name 需要进行授权验证的功能名称

中间件right是全局中间件,专门用于授权验证

菜单授权

CabloyJS对菜单授权采用白名单策略,所有授权都必须显式设置,系统管理员的授权也是如此

菜单授权有三种途径:

  1. 人工授权:如果某些权限只有在实际部署或运行时才能决定,可通过管理界面进行授权操作
  2. 初始授权:如果需要在系统运行时,预先初始化权限,可以在后端API路由version/init中通过代码分配权限。比如,给模版角色system分配权限
  3. 测试授权:为了测试与开发的便利,还可以在开发阶段预先初始化权限,可以在后端API路由version/test中通过代码分配权限。比如,给某些测试角色分配权限

在这里,我们通过初始授权,给角色root分配访问菜单kitchenSink的权限。角色root是角色树的根结点,给角色root授权,也就意味着所有用户(包括匿名用户)均可以访问此功能

src/module/test-party/backend/src/service/version.js

async init(options) {
  if (options.version === 3) {
    // roleFunctions
    const roleFunctions = [
      { roleName: 'root', name: 'kitchenSink' },
    ];
    await this.ctx.meta.role.addRoleFunctionBatch({ roleFunctions });
  }
}
名称 说明
options.version 模块数据版本,当模块编译并发布后,模块当前的数据版本建议处于封闭状态。如果有新的数据架构变更,递增数据版本。这样,随着业务模块的升级,模块内部的数据架构也将无缝升级