跳转到正文
Raven
返回

隐藏页面还不够:交付配置与账号权限如何共同生效

同一套业务系统经常需要交付不同版本。有的版本只包含订单列表,有的还包含统计报表;有的展示全部指标,有的只保留其中几项。与此同时,同一个版本里的管理员、普通成员和访客,能做的事情也不相同。

两组规则很容易被压进一个判断:没有权限,就把菜单隐藏。菜单确实变干净了,但页面内部的指标、导出按钮、直接访问的地址和后端接口,可能仍然保留着另一套逻辑。

这篇文章把模块化笔记中的结构问题整理成一个设计讨论。下文的订单系统、角色和配置键都是虚构例子,示意结构没有对应的已验证实现。

交付配置与账号权限回答不同的问题

假设一个订单系统有基础版和分析版。基础版没有订单趋势页面,分析版包含该页面。分析版中的普通成员可以看自己负责的订单,管理员可以看当前组织的订单并导出。

交付配置回答的是:这一份系统包含哪些能力? 账号权限回答的是:当前身份可以使用哪些能力? 数据范围继续约束:这次操作可以作用于哪些记录?

三者可以用一个概念表达式说明:

允许某次操作 = 交付能力开启
            且账号拥有对应操作权限
            且目标记录属于允许的数据范围

这是业务规则的分解,不是完整的鉴权代码。页面显示还需要考虑当前场景,而服务端必须对请求和具体对象做授权检查。不能因为账号看得到订单列表,就默认它能访问任意订单。OWASP 授权指南要求逐请求验证权限,并强调具体对象的访问检查。

交付配置关闭趋势分析时,组织管理员也不能通过管理员身份让它重新出现。管理员拥有的是当前交付范围内的管理权限。若确实需要维护人员的特殊入口,应另外定义身份与访问路径,避免让普通业务页面隐含一个“绕过所有限制”的分支。

先区分页面的配置方式

并不是每个页面都适合逐指标裁剪。可以按页面与内容的关系,先划出四类:

页面类型虚构例子变化方式
公共基础页面登录、个人设置保留入口,操作仍按身份判断
页面固定、内容可选订单列表页面保留,延迟数量等指标按配置出现
页面与内容均可选订单趋势页面可以关闭,开启后再选择指标
整体可选页面月度汇总报告整页开启或关闭,保持报告结构完整

这个分类的用途是把变化点说清楚。例如,关闭“延迟数量”不应让订单列表整页消失;关闭月度汇总报告,也不需要拆散报告中的每一段文字。

分类还影响空状态。如果订单趋势页面开启,但它依赖的指标全部关闭,就需要决定是禁止这份配置、隐藏空页面,还是显示明确的空状态。这个决定应该在配置规则里统一处理,否则导航、首页卡片和页面正文会各自猜测。

一个指标的影响通常跨越多个页面

“延迟数量”可能同时出现在订单列表、趋势图、详情卡片、告警设置和导出文件中。只给图表加一个开关,会留下名称仍可见、导出仍包含该字段或告警仍在发送等问题。

可以用一份能力登记表记录这些关联。它的作用是帮助检查影响范围,不是代替所有业务逻辑:

metric:late-orders:
  placements:
    - orders.column
    - trends.chart
    - order-detail.card
    - export.field
  linkedAlert: alert:late-orders
  dependentPage: page:trends

这份示意表里,placements 说明哪些位置消费该指标,linkedAlert 说明告警依赖,dependentPage 说明一个相关页面。真正实现时还需要规定依赖方向:页面关闭可以使该页面内的图表失效,但不能误伤订单列表里独立使用的同一指标。

新增指标时,开发者应能回答它会进入哪些位置、受哪些权限约束、会不会产生后台行为。这样,“关闭指标”才有明确范围,而不是在整个项目里凭记忆搜索名称。

构建裁剪、页面装配和接口授权分别验收

配置可以在构建时决定装入哪些模块,也可以在运行时决定展示哪些能力。选择哪一种,取决于交付方式和配置变化频率。无论采用哪种方式,都需要区分三个结果:

  1. 构建产物是否包含预期的页面和模块。
  2. 当前账号看到的入口、指标和操作是否正确。
  3. 服务端是否拒绝不允许的请求,并限制返回的数据范围。

关闭页面后,菜单消失只能证明一个界面变化。还应检查直接地址、首页快捷入口、历史书签、分享入口,以及访问接口的结果。即使页面模块已经从某个构建产物中移除,仍要独立检查可访问的服务端接口。

客户端可以提前做能力判断,避免无意义请求,也让用户理解为什么某项操作不可用。服务端则从可信的身份与配置中做决定,不把浏览器传来的“我有权限”当作依据。

分享访问需要自己的授权上下文

假设管理员把月度报告分享给外部访客。访客不应该因此继承管理员的订单编辑权,也不应该获得组织内全部报表的访问权。

在这个例子里,分享授权可以被明确限定为:某一份报告、只读访问、指定有效期,以及是否允许下载。分享入口本身也需要判断:当前交付是否包含分享能力,当前账号是否有权分享这份报告。

访问分享链接时,服务端再次确认分享是否有效、目标是否匹配、操作是否在授权范围内。页面原本属于哪个管理员,并不等于访客现在拥有什么权限。至于到期、撤销和原账号权限变化后如何处理,需要作为产品规则写清楚,再落实到检查逻辑中。

把配置和角色放进同一张验证表

按页面逐个点击,很容易只验证“开关有效”。更有用的是把交付配置与账号权限交叉起来:

交付能力账号权限应验证的结果
关闭有权限无业务入口,相关请求按产品规则拒绝
开启无权限无受限操作入口,直接请求被拒绝
开启有权限功能可用,结果仍受数据范围限制
关闭无权限页面和依赖内容均不应漏出

对指标再增加一层检查:关闭后,列表、图表、导出、阈值设置和告警行为是否一致。对分享增加另一组身份:匿名访客、链接已到期的访客、访问其他对象的访客。

这张表描述的是应该验证什么,并不意味着已经完成了这些检查。它能把“菜单没了”和“授权正确”分开记录,也能让一次配置变更的影响范围更容易复核。

交付版本增加时,不必急着为每个版本复制一套页面。先把能力、身份和数据范围各自的规则写清楚,再检查它们在页面、接口和分享访问上是否共同生效,模块化才有可维护的边界。



上一篇
Go 并发结果为什么每次不同:从共享计数到竞态检测
下一篇
用一个 C 小程序,看懂补码、字节序和浮点数