# 过滤器

# middleware(又名中间件)

# 什么是过滤器?

过滤器可以在业务云函数执行之前(或之后),统一拦截,进行过滤后再放行。

完整示例代码在目录 router/middleware/modules/ 目录下

# 我用自定义过滤器可以做什么?

# 自定义过滤器使用场景1 - 电商多店店铺管理系统后台

  • 1、使用自定义过滤器拦截当前登录用户
  • 2、检查该用户是否有权限操作该店铺
  • 3、如有权限,则同时将店铺信息直接回传给业务云函数
  • 4、在业务云函数的内置变量 filterResponse 中可直接获得当前操作的店铺的信息

# 框架内置的过滤器

无需配置,已自动生效,编写同ID的过滤器可以覆盖内置过滤器

过滤器ID 正则规则 层级 类型 说明
pub /pub/ 100 onActionExecuting 所有人都可以访问,不进行过滤
kh /kh/ 200 onActionExecuting 用户token过滤器,检测用户是否已登录
sys /sys/ 300 onActionExecuting 云函数层的权限过滤器,检测用户是否有此业务云函数的执行权限

# 中间件参数说明

参数 说明 类型 默认值 可选值
id 中间件ID,全局必须唯一,相同中间件ID会被覆盖 String - -
regExp 中间件的正则匹配规则(支持数组) String Array -
description 中间件的描述 String - -
index 中间件的执行顺序,值越小越先执行 Number - -
mode 中间件的模式,详情见下方 String onActionExecuting 见下方mode参数说明
enable 是否启动该中间件 Boolean false true
main 执行的函数 async function(event, serviceRes) - -

# mode参数说明

类型 说明
onActionExecuting 在action执行前执行
onActionExecuted 在action执行后执行
onActionIntercepted 在action被其他中间件拦截后执行
onActionError 在action执行异常时执行

# 自定义过滤器代码示例

# 单店版

/**
 * 店铺权限过滤器示例
 */
module.exports = [
  {
    id: "shopManage",
    regExp: "^client/shop/manage/(.*)",
    description: "店铺操作接口需要检测用户是否有权限",
    index: 310,// 此处必须>300 因为检测用户是否登录的过滤器的index是200(sys是300,因此为了能通用,建议填大于300的值)(越小越先执行)
    mode:"onActionExecuting", 
    enable:true, // 通过设置enable=false可以关闭该中间件
    main: async function(event) {
      let { util, filterResponse } = event;
      let { vk , db, _ } = util;
      let { uid, userInfo = {} } = filterResponse;
      if (vk.pubfn.isNull(userInfo) && uid) {
        // 如果userInfo为空,则通过uid获取用户信息(kh类型的云对象默认userInfo为空,需要手动获取)
        userInfo = await vk.daoCenter.userDao.findById(uid);
        filterResponse.userInfo = userInfo; // 将用户信息重新赋值给filterResponse.userInfo,方便云对象内执行this.getUserInfo();时无需再查库
      }
      let { role = [] } = userInfo;
      let res = { code : 0, msg : 'ok' };
      // 用户没有shopManage角色则拦截。(拦截后后面的云函数将不会运行,达到了简单的权限控制效果)
      if(role.indexOf("shopManage") === -1){
        return { code : -1, msg : '无权限' };
      }
      return res;
    }
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 多店版(多商家版本)

即用户A只能操作自己的店铺A,不可以操作店铺B

/**
 * 多店版(多商家版本)店铺权限过滤器示例,此仅为示例,实际需要修改成与你系统逻辑相符合才行。
 */
module.exports = [
  {
    id: "shopManage",
    // 这里代表的是哪些云函数需要进行判断权限
    regExp: [
      "^client/business/(.*)kh/",
      "^client/business/(.*)sys/"
    ],
    description: "需要判断用户是否有权限操作此店铺",
    index: 310,// 此处必须>300 因为检测用户是否登录的过滤器的index是200(sys是300,因此为了能通用,建议填大于300的值)(越小越先执行)
    mode:"onActionExecuting", 
    enable:true, // 通过设置enable=false可以关闭该中间件
    main: async function(event) {
      let { data = {}, util, filterResponse } = event;
      let { vk , db, _ } = util;
      let { uid, userInfo = {} } = filterResponse;
      if (vk.pubfn.isNull(userInfo) && uid) {
        // 如果userInfo为空,则通过uid获取用户信息(kh类型的云对象默认userInfo为空,需要手动获取)
        userInfo = await vk.daoCenter.userDao.findById(uid);
        filterResponse.userInfo = userInfo; // 将用户信息重新赋值给filterResponse.userInfo,方便云对象内执行this.getUserInfo();时无需再查库
      }
      let { shop_ids = [] } = userInfo;
      // 此 shop_id 为用户前端传过来的,因此我们需要在此进行判断,此用户是否有权限可操作这个该店铺
      let { shop_id } = data;
      let res = { code : 0, msg : 'ok' };
      if (vk.pubfn.isNull(shop_id)) {
        return { code : -1, msg : `店铺id不能为空` };
      }
      if (shop_ids.indexOf(shop_id) === -1) {
        return { code : -1, msg : `无权限操作店铺【${shop_id}` };
      }
      return res;
    }
  }
]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 常见问题

# 过滤器可以有很多种用途,权限判断只是其中一种用途,还可以

1、权限校验
2、统一对对外的接口进行加密、解密
3、写日志
4、对请求参数进行过滤处理
5、对返回给前端的数据进行过滤处理
6、等等
1
2
3
4
5
6

# 如何在业务函数获得过滤器传给业务函数的数据?


'use strict';
module.exports = {
  main: async(event) => {
    // filterResponse 为过滤器传给业务函数的数据
    let { filterResponse } = event;
    /**
     * 自定义过滤器检测了用户token已通过
     * 且通过用户token获得了用户信息和用户当前登录的店铺信息,并传给业务函数
     */
    let res = {
      code: 0,
      msg: '',
      shopInfo : filterResponse.shopInfo,
      userInfo : filterResponse.userInfo 
    };

   
    return res;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 如何在onActionExecuted类型的过滤器中获取云函数返回的数据?

/**
 * 自定义过滤器 - 后置
 */
module.exports = [
  {
    id: "xxxx2",
    regExp: "^xxx2/kh", // 正则匹配规则,这个是以^xxx2/kh/开头的云函数会被拦截
    description: "这里是你过滤器2号的描述",
    index: 310,// 此处必须>300 因为检测用户是否登录的过滤器的index是200(sys是300,因此为了能通用,建议填大于300的值)(越小越先执行)
    mode:"onActionExecuted",
    main: async function(event, serviceRes) {
      let { data = {}, util } = event;
      let { vk , db, _ } = util;
      // 这里的 serviceRes 即云函数将要返回给前端的数据
      serviceRes.msg = "被过滤器修改后的值";
      return serviceRes;
    }
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19