用户在前端调用后端接口是有安全风险的,开发者有责任管控接口以确保数据安全,不泄露给非授权用户。数据是企业的重要资产,加强数据安全就是保护企业资产。
只有特定权限的用户才可执行特定操作,数据不被非授权用户篡改、删除,确保数据只在最小范围内可被操作。比如用户表数据只有管理员或用户本人才可以修改
只有特定权限的用户才可查看特定字段,不暴露给本不该看到数据的人,确保数据只在最小范围内可见。比如用户表里的手机号和身份证只有管理员或用户本人才能查看,其他人只能看到用户必要的非机密信息(昵称、头像等)
只有特定条件下才可执行特定操作,确保数据处于正确的状态、符合业务要求。比如生成会员编号有唯一性要求;再比如如果文章作者保存的是用户id,删除了用户表中此作者的数据会导致无法显示作者姓名与头像。
多人在同一时刻同时更新同一数据时可能会破坏数据。比如给文章点赞时,如果是在客户端在当前文章点赞数的基础上加一后保存回数据库,那么在高并发状态下数据就会互相覆盖而让点赞数明显偏少。如果是在服务器端用$inc
操作符来给点赞数加一就可以避免这种错误。
记录数据操作历史可让数据改动可追踪,并具有不可抵赖性。类似于众触编辑器里的元数据的每次改动都记录着时间及其作者,可回滚到指定历史节点。开发者可根据需要酌情实现对业务表的追踪。
执行接口前会先执行【执行前】触发器以判断权限或者修正参数
有两个专门为此设计的函数okIf()
和ngIf()
符合就OK,马上执行接口不再执行剩余条件检查;不符就接着往下看
当条件condition
成立时允许当前用户立即执行该API而无需继续检查后续表达式,当条件不成立时继续检查后续表达式。select
可选字符串,是用空格隔开的多个字段,如果传了则会对返回内容进行选择/过滤;默认是只返回select里指定的字段,但如果exclude
为-1
时则表示要在返回结果中排除select里的字段。如果无select参数则返回所有数据。
如果是search查询的话则会用参数select替换查询选项option里面的select,当exclude
为-1
时会把select里面的每个字段前面添加减号。
okIf(user.role.includes("管理员") || auth == user._id) 如果调用者是管理员或此条数据的创建者则立即放行去执行API。
okIf(1, “phone x.身份证“, -1) 任何人都不可以查看手机和身份证(管理员或数据创建者已经在上一行放行,不在此语句的范围内)
符合就NG(Not Good),拒绝执行接口,马上返回前端;不符就接着往下看
当条件condition
成立时拒绝当前用户执行该API而立即返回前端,当条件不成立时继续检查后续表达式。
如果后面的参数不传,则返回403(无权限)给前端。msgType
是消息类型,warn/error/info/alert/notify
中的一个,title
是消息标题,txt
是消息文本(用于alert/notify)。
ngIf(!user.role.includes("管理员") && auth != user._id, “warn“, “非法“, “你无权操作,请联系管理员“)
通常前端要做过一次权限检查的,无权限的用户都应该看不到无权操作的按钮,不需要跑的后端来就立即得到了权限提示。这个函数是给安全兜底的,阻击另有目的的用户绕过前端黑到后端来。
ngIf
和stopIf
不同:stopIf()仅仅是停止执行当前表达式块的后续表达式;而ngIf()仅用在后端API的执行前条件中,用来判断用户是否有权限执行此后端API,所以它不仅停止执行后续表达式,更重要的是不再执行后端服务。
接口执行完会执行【执行后】触发器,转换最终返回前端的数据($x)或记录数据变更/日志处理等任务。
触发器有如下变量可供剩余
比如$product.get(id)里有id变量,$product.find(Q, O)里有查询条件Q和选项O变量。
即触发接口的用户,里面最常用到的字段是id
和role
。使用id可进一步从数据库获取此用户详细数据;role是角色数组,常用来判断用户的权限。另外iat
是issued at的缩写,是用户登录时给用户签发身份标识的时间(秒);exp
是expire的缩写,即用户身份标识的失效时间(秒),ai
是用户所在的appId,提供跨站服务的时候作为验证用户来源的依据。
执行前如果当前接口有id
参数时$x
就是用此id
从数据库拿到的最新数据,比如get(),delete(),update();
执行后$x
就是执行此接口返回的数据。
后端服务里的所有$exp表达式
如果update()接口会更新y
里的字段则isUpdatingY为真。
平台提供基础的默认配置以快速保障基本安全,开发者可以以此为模板进一步配置以满足复杂的业务安全需求。