权限检查放在哪里:从入口到异步返回
舒心读
18
卷中目录
权限判断最容易出现的缺口,是入口检查做得很认真,后续路径却默认这次判断永远有效。下载链接、缓存结果和长时间异步处理,都可能让这个假设暴露问题。
本篇目标: 用“主体、动作、对象”描述一次授权,并识别需要重新判断的时刻。

让授权规则有明确的对象
“这是管理员”或者“用户已经登录”,都不足以单独回答能否访问某份资料。应当明确当前主体要对哪个对象执行哪种动作,以及是否受空间、组织或可见范围限制。
主体:当前会话代表谁
动作:read / update / delete
对象:被操作的具体资源
条件:归属、范围、状态与有效期
把这些输入集中交给授权函数,比在各个接口散落不同的布尔判断更容易审查。默认拒绝没有明确规则的访问,能减少新增接口时意外继承宽权限的风险。
缓存不能省掉授权
缓存命中只是省去了重复计算或查询,不意味着可以跳过身份和对象范围检查。私人数据的缓存键与失效方式应考虑权限边界;不能因为两个请求参数相同,就把一个人的结果给另一个人。
下载票据也应绑定资源、有效期和必要的父身份。票据是否能独立访问,要在产品设计时明确,而不是由实现中的偶然缓存行为决定。
异步操作关注“开始”和“返回”
一个任务开始时被允许,结果返回时授权可能已经变化。是否需要重新检查,取决于任务会读取或输出什么,以及权限变化应何时生效。对持续输出的内容,还要设计撤权后停止后续输出的方式。
重新检查不必机械地等同于每个字节都访问数据库。可以使用受控的授权版本、短期授权上下文或事件通知,但必须明确失效条件和一致性要求。
用反例审查接口
尝试访问不属于自己的对象、在任务等待时撤销权限、让旧下载链接在重新登录后继续使用、让旧请求的错误在新会话建立后才返回。观察系统是否只影响对应旧上下文。
最后检查日志:记录授权决策所需的最少线索即可,不要把完整身份凭据写出来。权限设计的目标,是让每一条数据路径都能说明为什么被允许,而不是让用户记住哪些入口“最好别点”。
见字如晤