总纲立完,本节动手发门禁卡。Capabilities 是 Tauri 2 权限体系的落地形态:一个 JSON 文件声明"哪个窗口能用哪些命令、作用域到哪"。本节给随身笔记写出真实的能力文件,走一遍"申请、授予、回收、排错"的完整循环。读完本节,"权限怎么配"从查文档猜语法变成一套固定工序。
能力文件放 src-tauri 的 capabilities 目录,脚手架自带一个 default.json。结构三要素:windows(授权给哪些窗口标签)、permissions(授权哪些命令权限)、可选的 remote(是否授予远程页面)。给随身笔记写一份:
{ "identifier": "main-notes", "windows": ["main"], "permissions": [ "core:default", "core:window:allow-minimize", "core:window:allow-toggle-maximize", "core:window:allow-close", "dialog:allow-save", { "identifier": "fs:allow-read-text-file", "allow": [{ "path": "$APPDATA/notes/*" }] }, { "identifier": "fs:allow-write-text-file", "allow": [{ "path": "$APPDATA/notes/*" }] } ] }
逐行读:windows: ["main"] 把本清单绑定到主窗——4.4 创建的 editor 窗口不在授权范围内,它连 minimize 都调不了,除非另立清单;core:default 是核心默认集(事件、资源协议等基础项,不含窗口操作);窗口三连是我们 4.4 自绘标题栏用到的命令;dialog 只授 save;fs 读写权限各自带作用域。$APPDATA 是路径变量,解析为系统应用数据目录(随 identifier),作用域精确到笔记子目录——6.1 判据三的落地。
需求演变是权限管理的日常。设想两个真实迭代:
迭代一:编辑窗口需要读笔记。 editor 窗口要展示正文,读文件能力给它。新建清单而非扩旧清单——信任域按窗口分开:
{ "identifier": "editor-notes", "windows": ["editor-*"], "permissions": [ "core:default", { "identifier": "fs:allow-read-text-file", "allow": [{ "path": "$APPDATA/notes/*" }] } ] }
注意 windows 支持 editor-* 通配——多实例编辑窗(editor-42 这类标签)一批授权。它拿得到读,拿不到写:编辑窗提交保存走命令(芯侧校验后落盘),不给前端直写权。
迭代二:砍掉运行中的功能,权限同步回收。 需求砍掉了导出功能,dialog 的 save 权限从主窗清单删除。权限回收和功能删除是同一个提交——留下没用的授权等于在门上留一把没人管的钥匙。

作用域支持精确路径、通配与排除。常用路径变量按 OS 解析到正确位置:APPDATA**(应用数据目录)、**APPCONFIG(应用配置目录)、DOCUMENT**(用户文档)、**HOME(用户主目录,慎用)、DESKTOP**、**DOWNLOAD。写法三则:$APPDATA/notes/* 允许目录下全部条目;递归深目录用双星;"requireLiteralLeadingDot" 类选项控制隐藏文件匹配。排除用 deny 列表压过 allow——允许笔记目录但排除某个缓存子目录,就这么写。
权限不足的前端症状是统一的 rejected 调用,错误信息常含权限标识符。三条排错路径按序走:一看窗口标签对不对——通配写错、大小写不匹配、窗口创建时标签改了名,都会"查无此窗";二看权限标识符拼写——插件权限带插件前缀(dialog:allow-save),漏前缀等于不存在;三看作用域——权限对了但路径变量解析结果与预期不符,把作用域里的路径展开核对。开发期的一个好习惯:每接入一个新插件,就同一次提交里写好最小权限清单,跑通后立即审视能否再减。
排错三看是事后排查,这里把事前预防做掉——下面四种错配在真实项目里反复出现,症状与修正对应着前文的机制:
| 错配 | 运行症状 | 根因与修正 |
|---|---|---|
| 权限加了、窗口标签没加 | 命令在 A 窗好用、B 窗全拒 | 清单只绑了 main;为 B 窗补清单或扩 windows 通配 |
作用域写 $APPDATA 忘了子目录 | 目录整体可读写 | 作用域过宽;收到 $APPDATA/notes/* 级别 |
||
| 手抄权限标识符漏前缀 | 构建期或运行期"权限不存在" | 插件权限必须带 插件名:allow-xxx 前缀;以插件文档为准 |
| 开发期图省事拷来一份大而全清单 | 一切正常,直到安全评审 | 授权集远超功能集;按 6.1 三判据重裁 |
四种错配有一个共同解法:让权限变更走代码评审。清单文件与功能代码同仓库同提交,评审者看到 dialog:allow-save 被删除时,应当能在同一 diff 里找到导出功能被删的证据——对不上就是多发卡。这套纪律成本极低(只是别把清单改动混进无关提交),却把"权限与功能一致"从口号变成了可检查的机械事实。
还有一条关于升级的:插件大版本升级可能引入新命令或调整权限粒度,升级依赖后应重跑一遍 6.1 判据一——旧清单是按旧粒度裁的,新粒度下可能出现"一个权限背后塞进了三个命令"的情况,及时拆细。
门禁卡发好了。下一节补壳的加载边界:CSP 的字段语义、自动 nonce 注入,以及 XSS 如何被拦在升级成 RCE 之前。