钩子函数与接口安全

用户在前端调用后端接口是有安全风险的,开发者有责任管控接口以确保数据安全,不泄露给非授权用户。数据是企业的重要资产,加强数据安全就是保护企业资产。

考虑要点

安全性

只有特定权限的用户才可执行特定操作,数据不被非授权用户篡改、删除,确保数据只在最小范围内可被操作。比如用户表数据只有管理员或用户本人才可以修改

机密性

只有特定权限的用户才可查看特定字段,不暴露给本不该看到数据的人,确保数据只在最小范围内可见。比如用户表里的手机号和身份证只有管理员或用户本人才能查看,其他人只能看到用户必要的非机密信息(昵称、头像等)

完整性

只有特定条件下才可执行特定操作,确保数据处于正确的状态、符合业务要求。比如生成会员编号有唯一性要求;再比如如果文章作者保存的是用户id,删除了用户表中此作者的数据会导致无法显示作者姓名与头像。

并发性

多人在同一时刻同时更新同一数据时可能会破坏数据。比如给文章点赞时,如果是在客户端在当前文章点赞数的基础上加一后保存回数据库,那么在高并发状态下数据就会互相覆盖而让点赞数明显偏少。如果是在服务器端用$inc操作符来给点赞数加一就可以避免这种错误。

执行前拦截函数

执行接口前会先执行【执行前】拦截以验证调用者权限,修正参数,甚至阻止接口调用。
有两个专门为此设计的函数okIf()ngIf()

okIf(条件, 字段, 排除)

符合就OK,马上执行接口不再执行剩余条件检查;不符就接着往下看
当条件成立允许当前用户立即执行该API而无需继续检查后续表达式,当条件不成立时继续检查后续表达式。
字段可选,是用逗号隔开的多个字段,如果传了则会只返回它指定的字段,但如果排除-1时则表示要在返回结果中排除前面指定的字段。
okIf(me.role.includes("管理员") || auth == me.id) 如果调用者是管理员或此条数据的创建者则立即放行去执行API。
okIf(1, "phone, x.身份证", -1)   任何人都不可以查看手机和身份证(管理员或数据创建者已经在上一行放行,不在此语句的范围内)

ngIf(条件, 消息类型, 消息标题, 消息内容)

符合就NG(Not Good,拒绝执行接口,马上返回前端;不符就接着往下看
当条件成立时拒绝当前用户执行该API而立即返回前端,当条件不成立时继续检查后续表达式。
如果后面的参数不传,则返回403(无权限)给前端。
消息类型是warn/error/info/alert/notify中的一个,alert/notify可以传入消息内容。
ngIf(!me.role.includes("管理员") && auth != me.id, "warn", "非法", "你无权操作,请联系管理员")

通常前端要做过一次权限检查的,无权限的用户都应该看不到无权操作的按钮,不需要跑的后端来就立即得到了权限提示。这个函数是给安全兜底的,阻击另有目的的用户绕过前端黑到后端来。

ngIfstopIf不同:stopIf()仅仅是停止执行当前表达式块的后续表达式;而ngIf()仅用在后端API的执行前条件中,用来判断用户是否有权限执行此后端API,所以它不仅停止执行后续表达式,更重要的是不再执行后端服务。

执行后处理

接口执行完后会执行【执行后】钩子函数,如转换最终返回前端的数据($x)或记录数据变更/日志处理等任务。

环境变量

触发器有如下变量可供剩余

接口参数

比如$product.get(id)里有id变量,$product.find(Q, O)里有查询条件Q和选项O变量。

me

即触发接口的用户(前端登录用户,简化版$c.me),里面最常用到的字段是idrole。使用id可进一步从数据库获取此用户详细数据;role是角色数组,常用来判断用户的权限。另外iatissued at的缩写,是用户登录时给用户签发身份标识的时间(秒);expexpire的缩写,即用户身份标识的失效时间(秒),ai是用户所在的appId,提供跨站服务的时候作为验证用户来源的依据。

$x

执行前如果当前接口有id参数时$x就是用此id从数据库拿到的最新数据,比如get(),delete(),update();
执行后$x就是执行此接口返回的数据。

$exp

后端服务里的所有$exp表达式

isUpdatingY

如果update()接口会更新y里的字段则isUpdatingY为真。

默认配置

平台提供基础的默认配置以快速保障基本安全,开发者可以以此为模板进一步配置以满足复杂的业务安全需求。

由众触低代码平台生成和驱动