构建

这个谁能按 — 把按钮藏起来不是权限

作者: makemind · 2026年7月9日

门店 POS 上有个「撤销销售」按钮。只有店长该按。

一般是这么做的:如果登录的人是店员,就不画那个按钮。

然后管这叫权限处理。它不是。

不画它什么也拦不住

不画按钮拦住的只是「按那个按钮把请求发出去」这一条路径。 请求可以从别处发出。画面定义可以改,甚至完全不要画面直接调工具也行。画面是客户端,而客户端是别人的。

所以这个样例反着来。把按钮给两个人都看。

SIGNED IN AS STAFF — 4 sales · 9.6k won. Ring / Void last sale / Open drawer. voided 0 · refused 2
SIGNED IN AS STAFF — 4 sales · 9.6k won. Ring / Void last sale / Open drawer. voided 0 · refused 2

这是店员的画面。「Void last sale」和「Open drawer」都原样在那儿。按得下去。

按下去是这样。

[staff] sale.ring   -> "rang 3000"                        (sales=4 voided=0 refused=0)
[staff] sale.void   -> "sale.void is not yours to press"  (sales=4 voided=0 refused=1)
[staff] drawer.open -> "drawer.open is not yours to press"(sales=4 voided=0 refused=2)

卖是卖成了,撤销没成。 不是画面拦住的,是服务器没做。

店长打开同一个画面

SIGNED IN AS MANAGER — 3 sales · 6.6k won. voided 1 · refused 0
SIGNED IN AS MANAGER — 3 sales · 6.6k won. voided 1 · refused 0
[manager] sale.ring   -> "rang 3000"     (sales=4 voided=0 refused=0)
[manager] sale.void   -> "voided 3000"   (sales=3 voided=1 refused=0)
[manager] drawer.open -> "drawer opened" (sales=3 voided=1 refused=0)

同样的按钮、同样的顺序、不同的结果。

而且画面文件是同一个文件。 这正是这一篇的主张,所以测试装置把哈希打了出来。

screen ui/pages/register.json sha256:72288a2c655a — one file, both roles
the screen offers 3 buttons and shows all of them to everyone

角色不是参数

这是这个样例里唯一的设计决定。

/// Who this session is. Fixed for its lifetime, never taken from a call.
final String role;

假设 sale.voidrole 当参数收。

sale.void { "role": "manager" }

那么任何能调用它的人都可以自称是店长。 那一刻真正在拦着的,就只剩「画面不发这个值」,于是我们又回到了「不画按钮」。

所以角色在会话打开时就定下来。在这个样例里是启动参数,在真实部署里则是那条连接所认证到的身份。

final role = args
    .firstWhere((a) => a.startsWith('--role='), orElse: () => '--role=staff')
    .substring('--role='.length);

画面不发送角色。就算想发也发不了。

验证守住这一点 — 画面定义里一旦出现角色名,就判失败。

# The screen may *display* the role it was told. It must never name one — the
# moment "manager" or "staff" appears in a screen definition, some branch is
# being decided in the wrong place.
if grep -qiE '"[^"]*(manager|staff)' register.mbd/ui/pages/register.json; then
  echo "   the screen definition names a role — the rule has leaked out of the tool"
  exit 1
fi

画面显示 {{role}}。那是把服务器告诉它的东西画出来,它不决定任何事。

此内容需要开发者或更高等级

登录并升级您的方案即可继续阅读。

查看方案
Twitter