多人协作如何避免越权和覆盖?运维 SaaS 的权限与并发控制
用户可以登录,并不代表可以访问每个项目;两人都有编辑权,也不代表后保存者可以覆盖前一人的修改。本文以设备台账与工单为例,区分身份、空间权限、对象归属、订阅资格和版本条件,梳理关键校验顺序。
多人协作的运维平台需要回答两类问题:这个人能否执行操作,以及他提交修改时所依据的数据是否仍然有效。前者是权限问题,后者是并发一致性问题。只处理其中之一,仍可能出现跨项目访问、会员功能绕过或同事修改被悄悄覆盖。
登录、角色与订阅资格要分别判断
登录确认当前身份;空间成员关系确定组织范围;角色或对象策略决定可以做什么;订阅资格决定当前是否具备某项服务权益。这些判断相关,但不能互相替代。
例如一个用户在甲企业是管理员,在乙企业只是访客。切换空间后,应重新按乙企业的成员关系判断权限,不能把甲企业角色带过去。企业拥有某项订阅,也不意味着每个成员都应自动拥有删除全部资料的权限。
OWASP 的多租户安全指南明确指出,客户端传入的租户标识只能用于选择范围,必须结合服务端验证的身份与成员资格作出授权判断。OWASP:Multi-Tenant Security
把校验放在每个真实操作入口
前端隐藏按钮改善使用体验,但不能替代接口校验。查询、下载、修改、批量导出、分享和异步任务都可能访问同一份数据,应遵循一致的授权边界。
| 检查层次 | 需要核对的问题 |
|---|---|
| 当前身份 | 会话是否有效,账号是否停用? |
| 当前空间 | 是否仍是该空间的有效成员? |
| 目标对象 | 设备、资料或工单是否属于允许范围? |
| 操作能力 | 当前角色能否执行这个具体动作? |
| 业务条件 | 状态、订阅及版本条件是否满足? |
长时间运行的任务还应在敏感写入或结果下载前复核必要条件。用户提交任务后被移出企业,不能仅凭提交时的一次判断永久获得结果访问权。
用对象版本防止静默覆盖
设想两位人员同时打开一条设备记录,看到版本 8。甲更新安装位置并保存为版本 9;乙稍后提交基于版本 8 的旧表单。如果服务端直接覆盖全部字段,甲的修改就会丢失。
一种常见设计是带版本条件更新:请求携带读取时的版本,服务端在原子写入时比较当前版本。条件不满足则返回冲突,由用户查看差异后重新提交。HTTP 的 If-Match 条件请求就是防止此类丢失更新的标准机制之一。IETF:RFC 9110,If-Match
实现可以采用版本字段或合适的实体标签,但必须把比较与写入放在同一个原子边界内。“先查询版本,再过一会儿写入”仍可能在中间发生竞争。
冲突提示应帮助继续工作
发现版本冲突后,不宜只显示“保存失败”,更不能自动覆盖。编辑器可以保留用户尚未提交的内容,指出哪些字段已被他人修改,并提供刷新后核对的路径。
对工单状态,除了版本外还应检查合法流转。例如已关闭任务不能被旧页面直接改回执行中;审批被撤回后,旧窗口中的“通过”操作也应重新验证当前条件。字段修改和状态变更使用不同规则,能减少一个通用更新接口承担过多隐含逻辑。
权限变化也可能发生在用户编辑期间。此时应先保证受保护的数据没有被写入,再以清楚的提示说明当前权限已变化,而不是为了保留编辑体验继续接受旧授权。
缓存、文件与队列同样需要边界
数据库查询带了空间条件,并不代表整条链路已经隔离。缓存键、文件访问、导出结果和队列任务都要绑定合适的空间与授权范围。随机文件名只能降低猜测便利,不能证明访问者有权下载。
对有时效的下载链接,应明确有效期、对象范围与撤销条件。对于数据变化频繁或权限要求较高的资源,可采用每次访问时验证权限的方式。选择哪种方案应结合使用场景,并把实际边界写进测试。
操作日志宜保留操作者、空间、对象、动作、结果与必要的变更摘要,不应把密码、会话令牌或完整敏感文件内容写进日志。日志自身也需要受限访问和适当保留策略。
用交叉组合验证业务逻辑
验收时至少覆盖:同一用户在两个空间角色不同、成员被移除后继续使用旧页面、订阅状态变化后重复调用、跨空间替换对象 ID、两个用户并发编辑,以及网络超时后的重试。
每个用例都应检查接口结果和实际数据状态,不能只观察按钮是否消失。对于失败操作,还应确认没有残留文件、重复记录或部分完成的业务状态。
在梳理角色与任务时,可结合设备台账到工单闭环确定真实流程。可靠协作来自每个入口对同一业务规则的持续执行,而不仅是一张角色权限表。
