同一套业务系统经常需要交付不同版本。有的版本只包含订单列表,有的还包含统计报表;有的展示全部指标,有的只保留其中几项。与此同时,同一个版本里的管理员、普通成员和访客,能做的事情也不相同。
两组规则很容易被压进一个判断:没有权限,就把菜单隐藏。菜单确实变干净了,但页面内部的指标、导出按钮、直接访问的地址和后端接口,可能仍然保留着另一套逻辑。
这篇文章把模块化笔记中的结构问题整理成一个设计讨论。下文的订单系统、角色和配置键都是虚构例子,示意结构没有对应的已验证实现。
交付配置与账号权限回答不同的问题
假设一个订单系统有基础版和分析版。基础版没有订单趋势页面,分析版包含该页面。分析版中的普通成员可以看自己负责的订单,管理员可以看当前组织的订单并导出。
交付配置回答的是:这一份系统包含哪些能力? 账号权限回答的是:当前身份可以使用哪些能力? 数据范围继续约束:这次操作可以作用于哪些记录?
三者可以用一个概念表达式说明:
允许某次操作 = 交付能力开启
且账号拥有对应操作权限
且目标记录属于允许的数据范围
这是业务规则的分解,不是完整的鉴权代码。页面显示还需要考虑当前场景,而服务端必须对请求和具体对象做授权检查。不能因为账号看得到订单列表,就默认它能访问任意订单。OWASP 授权指南要求逐请求验证权限,并强调具体对象的访问检查。
交付配置关闭趋势分析时,组织管理员也不能通过管理员身份让它重新出现。管理员拥有的是当前交付范围内的管理权限。若确实需要维护人员的特殊入口,应另外定义身份与访问路径,避免让普通业务页面隐含一个“绕过所有限制”的分支。
先区分页面的配置方式
并不是每个页面都适合逐指标裁剪。可以按页面与内容的关系,先划出四类:
| 页面类型 | 虚构例子 | 变化方式 |
|---|---|---|
| 公共基础页面 | 登录、个人设置 | 保留入口,操作仍按身份判断 |
| 页面固定、内容可选 | 订单列表 | 页面保留,延迟数量等指标按配置出现 |
| 页面与内容均可选 | 订单趋势 | 页面可以关闭,开启后再选择指标 |
| 整体可选页面 | 月度汇总报告 | 整页开启或关闭,保持报告结构完整 |
这个分类的用途是把变化点说清楚。例如,关闭“延迟数量”不应让订单列表整页消失;关闭月度汇总报告,也不需要拆散报告中的每一段文字。
分类还影响空状态。如果订单趋势页面开启,但它依赖的指标全部关闭,就需要决定是禁止这份配置、隐藏空页面,还是显示明确的空状态。这个决定应该在配置规则里统一处理,否则导航、首页卡片和页面正文会各自猜测。
一个指标的影响通常跨越多个页面
“延迟数量”可能同时出现在订单列表、趋势图、详情卡片、告警设置和导出文件中。只给图表加一个开关,会留下名称仍可见、导出仍包含该字段或告警仍在发送等问题。
可以用一份能力登记表记录这些关联。它的作用是帮助检查影响范围,不是代替所有业务逻辑:
metric:late-orders:
placements:
- orders.column
- trends.chart
- order-detail.card
- export.field
linkedAlert: alert:late-orders
dependentPage: page:trends
这份示意表里,placements 说明哪些位置消费该指标,linkedAlert 说明告警依赖,dependentPage 说明一个相关页面。真正实现时还需要规定依赖方向:页面关闭可以使该页面内的图表失效,但不能误伤订单列表里独立使用的同一指标。
新增指标时,开发者应能回答它会进入哪些位置、受哪些权限约束、会不会产生后台行为。这样,“关闭指标”才有明确范围,而不是在整个项目里凭记忆搜索名称。
构建裁剪、页面装配和接口授权分别验收
配置可以在构建时决定装入哪些模块,也可以在运行时决定展示哪些能力。选择哪一种,取决于交付方式和配置变化频率。无论采用哪种方式,都需要区分三个结果:
- 构建产物是否包含预期的页面和模块。
- 当前账号看到的入口、指标和操作是否正确。
- 服务端是否拒绝不允许的请求,并限制返回的数据范围。
关闭页面后,菜单消失只能证明一个界面变化。还应检查直接地址、首页快捷入口、历史书签、分享入口,以及访问接口的结果。即使页面模块已经从某个构建产物中移除,仍要独立检查可访问的服务端接口。
客户端可以提前做能力判断,避免无意义请求,也让用户理解为什么某项操作不可用。服务端则从可信的身份与配置中做决定,不把浏览器传来的“我有权限”当作依据。
分享访问需要自己的授权上下文
假设管理员把月度报告分享给外部访客。访客不应该因此继承管理员的订单编辑权,也不应该获得组织内全部报表的访问权。
在这个例子里,分享授权可以被明确限定为:某一份报告、只读访问、指定有效期,以及是否允许下载。分享入口本身也需要判断:当前交付是否包含分享能力,当前账号是否有权分享这份报告。
访问分享链接时,服务端再次确认分享是否有效、目标是否匹配、操作是否在授权范围内。页面原本属于哪个管理员,并不等于访客现在拥有什么权限。至于到期、撤销和原账号权限变化后如何处理,需要作为产品规则写清楚,再落实到检查逻辑中。
把配置和角色放进同一张验证表
按页面逐个点击,很容易只验证“开关有效”。更有用的是把交付配置与账号权限交叉起来:
| 交付能力 | 账号权限 | 应验证的结果 |
|---|---|---|
| 关闭 | 有权限 | 无业务入口,相关请求按产品规则拒绝 |
| 开启 | 无权限 | 无受限操作入口,直接请求被拒绝 |
| 开启 | 有权限 | 功能可用,结果仍受数据范围限制 |
| 关闭 | 无权限 | 页面和依赖内容均不应漏出 |
对指标再增加一层检查:关闭后,列表、图表、导出、阈值设置和告警行为是否一致。对分享增加另一组身份:匿名访客、链接已到期的访客、访问其他对象的访客。
这张表描述的是应该验证什么,并不意味着已经完成了这些检查。它能把“菜单没了”和“授权正确”分开记录,也能让一次配置变更的影响范围更容易复核。
交付版本增加时,不必急着为每个版本复制一套页面。先把能力、身份和数据范围各自的规则写清楚,再检查它们在页面、接口和分享访问上是否共同生效,模块化才有可维护的边界。