校验器

校验器用于数据操作时校验操作的合法性,是对数据表 ACL 权限的自定义校验。 数据表关联了校验器后,在进行数据操作时,后台会调用该校验器进行校验。 校验器通过返回 truefalse 或抛出错误来对操作合法性做出评判。

校验器的使用场景主要分为以下几个方面:

  • 对数据表操作方法进行校验(createupdatedeletebulk_createbulk_updatebulk_delete等)
  • 对操作者进行校验
  • 对用户传入数据—— payload 进行校验

info 3.13.0 版本前,校验器 payload 字段可以拿到整个数据对象;

3.13.0 版本后(包括 3.13.0),校验器 payload 字段仅能拿到用户输入数据。

快速开始

只需两步,即可成功创建校验器:

  1. 在控制台数据表中创建校验器 查看文档
  2. 校验器创建成功后,进入编辑页面,只需要在默认提供的校验器模版代码对应的 handler 如 onCreate 中加入判定逻辑即可,校验器模版代码如下。

    1. BaaS.useVersion('v3.4')
    2. exports.main = async function (event) {
    3. const handlers = {
    4. /**
    5. * handler 会在对应的操作事件中被触发,请在下方对应的事件 handler 如 onCreate 中添加判定逻辑并修改返回值。
    6. *
    7. * <<输入>>:
    8. * | 属性 | 类型 | 说明 |
    9. * | :---------- | :----- | :-------------------------------------------------------------------------------------------- |
    10. * | event | String | 触发事件类型,包括:`create`、`update`、`delete`、`bulk_create`、`bulk_update`、`bulk_delete` |
    11. * | schema_id | String | 校验器关联的数据表 ID |
    12. * | schema_name | String | 校验器关联的数据表名称 |
    13. * | user_id | String | 触发事件的用户 ID |
    14. * | payload | Object | 用户传入数据,`delete`/`bulk_delete` 事件中不包含该参数 |
    15. * | before | Object | 原始数据,`create`/`bulk_create`/`bulk_update`/`bulk_delete` 事件中不包含该参数 |
    16. * | filter | Object | 用户筛选条件,仅 `bulk_update`/`bulk_delete` 包含该参数 |
    17. *
    18. * <<输出>>:
    19. * 返回 true 为 “验证通过”
    20. * 返回 false 为 “验证不通过(未提供理由)”
    21. * 抛出 Error 为 “验证不通过(Error.message 为理由)”
    22. *
    23. * <<举例>>:
    24. * return data.user_id == 1001 // 只允许 ID 为 1001 的用户进行操作
    25. * 或者:
    26. * if (data.user_id == 1001) {
    27. * return true
    28. * } else {
    29. * throw Error(`用户 ${data.user_id} 无操作权限`)
    30. * }
    31. */
    32. async onCreate(data) {
    33. // “创建”操作时触发,
    34. return true
    35. },
    36. async onUpdate(data) {
    37. // “更新”操作时触发
    38. return true
    39. },
    40. async onDelete(data) {
    41. // “删除”操作时触发
    42. return true
    43. },
    44. async onBulkCreate(data) {
    45. // “批量创建”操作时触发
    46. return true
    47. },
    48. async onBulkUpdate(data) {
    49. // “批量更新”操作时触发
    50. return true
    51. },
    52. async onBulkDelete(data) {
    53. // “批量删除”操作时触发
    54. return true
    55. },
    56. }
    57. const validator = new BaaS.Validator(handlers)
    58. return validator.validate(event)
    59. }

使用示例

下方是一个完整的校验器例子,实现了以下规则:

  • 所有用户可以创建订单
  • 只允许用户 1001 删除订单
  • 禁止了批量创建、批量更新、批量删除
  • 禁止取消已过期订单
  1. BaaS.useVersion('v3.4')
  2. exports.main = async function (event) {
  3. const handlers = {
  4. async onCreate(data) {
  5. return true
  6. },
  7. async onUpdate(data) {
  8. if (event.data.before.status === '已过期' && event.data.payload.status === '已取消') {
  9. throw Error('已过期的订单不可取消')
  10. }
  11. return true
  12. },
  13. async onDelete(data) {
  14. if (data.user_id == 1001) {
  15. return true
  16. } else {
  17. throw Error(`用户 ${data.user_id} 无操作权限`)
  18. }
  19. },
  20. async onBulkCreate(data) {
  21. return false
  22. },
  23. async onBulkUpdate(data) {
  24. return false
  25. },
  26. async onBulkDelete(data) {
  27. return false
  28. },
  29. }
  30. const validator = new BaaS.Validator(handlers)
  31. return validator.validate(event)
  32. }

Validator

SDK 提供了 Validator 类来帮助开发者快速实现校验器。

info SDK >= v3.4。

  • Validator(handlers) 创建 Validator 对象
  • Validator#validate(event) 执行校验

参数说明

属性 类型 必填 说明
handlers Handlers 数据表操作 handler 集合
event Object 云函数 event 参数

Handlers:

  1. interface Handlers {
  2. [key: string]: (data: typeof event.data) => boolean
  3. }
  • event.data 的数据结构,请参照 event.data 说明
  • key 的规则是:'on_' + 操作事件名,再转化为 CamelCase。例如:onCreateonBulkCreate

info 某个操作事件的 handler 如果未定义,默认返回 true。

使用方法:

  1. 创建 Validator 对象

    const validator = new Validator(handlers)

  2. 执行校验并返回结果

    return validator.validate(event)

代码示例

参考上文。

高阶使用

除了直接使用 Validator 类,开发者还可用自定义逻辑实现校验器。

event.data说明

校验器的 event.data 参数中,包含了触发该校验器的数据操作的详细信息,校验器可以对这些信息进行校验,最终给出判定。

属性 类型 说明
event String 触发事件类型,包括:createupdatedeletebulk_createbulk_updatebulk_delete
schema_id String 校验器关联的数据表 ID
schema_name String 校验器关联的数据表名称
user_id String 触发事件的用户 ID
payload Object 用户传入数据,delete/bulk_delete 事件中不包含该参数
before Object 原始数据,create/bulk_create/bulk_update/bulk_delete 事件中不包含该参数
filter Object 用户筛选条件,仅 bulk_update/bulk_delete 包含该参数

event.data.event 说明:

属性 说明
create 创建
update 更新
delete 删除
bulk_create 批量创建
bulk_update 批量更新
bulk_delete 批量删除

返回说明

返回 说明
true 合法操作,校验通过
false 非法操作,校验不通过(未提供拒绝理由)
<Error> 非法操作,校验不通过(Error.message 为拒绝理由)

拒绝所有操作/允许所有操作

校验器直接返回判定结果。

代码示例

不返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. exports.main = async function (event) {
  3. return false
  4. }

返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. exports.main = async function (event) {
  3. throw '数据表已锁定,不允许任何操作'
  4. }

对数据表操作方法进行校验

校验器中默认所有操作方法都是打开的,如果需要关闭某个或某写方法的操作权限, 只需要判断操作方法并返回 false 即可。

代码示例

不返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. const whitelist = ['create', 'update']
  3. exports.main = async function (event) {
  4. return whitelist.includes(event.data.event)
  5. }

返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. const whitelist = ['create', 'update']
  3. exports.main = async function (event) {
  4. if (!whitelist.includes(event.data.event)) {
  5. throw Error(`不允许 ${event.data.event} 操作`)
  6. }
  7. return true
  8. }

对操作者进行校验

对操作者进行验证与数据表操作方法验证类似,判定并返回判定结果即可。

代码示例

不返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. const whitelist = [1001, 1002]
  3. exports.main = async function (event) {
  4. return whitelist.includes(event.data.user_id)
  5. }

返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. const whitelist = [1001, 1002]
  3. exports.main = async function (event) {
  4. if (!whitelist.includes(event.data.user_id)) {
  5. throw Error(`用户 ${event.data.user_id} 无操作权限`)
  6. }
  7. return true
  8. }

对用户传入数据进行校验

对用户传入数据进行校验时,一般是通过与更新前的数据进行对比,或通过数据查询,判定操作是否合法。

代码示例

不返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. exports.main = async function (event) {
  3. return !(event.data.before.status === '已过期' && event.data.payload.status === '已取消')
  4. }

返回拒绝理由:

  1. BaaS.useVersion('v3.4')
  2. exports.main = async function (event) {
  3. if (event.data.before.status === '已过期' && event.data.payload.status === '已取消') {
  4. throw Error('已过期的订单不可取消')
  5. }
  6. return true
  7. }

注意事项

  1. “校验器”与“云函数”使用同一个“云函数”引擎,但使用场景并不一样, 不要在“校验器”中包含跟数据校验无关的业务代码

  2. 由于 JavaScript 函数默认返回 undefined,是个 falsy 值,所以校验通过时,需要明确返回 true

    例如,下文的代码中,开发者的意图是只禁止 ID 为 1001 的用户创建数据。但实际上, 所有用户都被禁止操作了。

    1. ...
    2. async onCreate(data) {
    3. if (data.user_id == 1001) {
    4. return false
    5. }
    6. },
    7. ...

    正确的做法:

    1. ...
    2. async onCreate(data) {
    3. if (data.user_id == 1001) {
    4. return false
    5. }
    6. return true
    7. },
    8. ...