权限模型:Capability 与作用域

Tauri 2.x 最重要的变化就是权限模型。1.x 的 allowlist 是一组全局开关,2.x 的 Capability 则是「谁能对谁做什么」的精确声明。理解它,才能既给前端足够的能力,又不把整个系统暴露出去。本篇讲 Capability 文件结构、作用域机制与常见配置示例。

一、设计思路:默认拒绝

Tauri 2 的安全起点是「前端默认没有任何能力」。每调用一个插件 API、每访问一个目录,都必须先在 Capability 文件中声明。声明以 JSON 形式存放在 src-tauri/capabilities/ 目录,编译期打包进应用。

这套模型的三个概念:

概念 含义
Permission 插件定义的权限单元,如 fs 的 allow-read
Scope 权限的作用范围,如允许访问的目录
Capability 一组 permission 与 scope 的集合,绑定到窗口或应用

默认生成的项目里通常有一个 default.json,给主窗口开启基础能力。新增插件能力时就是改这个文件。

二、Capability 文件结构

一个典型示例如下:

{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "主窗口默认能力",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "fs:allow-read-text-file",
    {
      "identifier": "fs:allow-write",
      "allow": [
        { "path": "$APPDATA/*" }
      ]
    },
    "notification:default"
  ]
}

identifier 唯一标识这份能力集,windows 决定它作用于哪些窗口。permission 既可以直接写字符串,也可以带 allow 或 deny 列表做作用域控制。具体每个插件提供哪些 permission,参考其文档或编译时生成的 schema 文件,以官方文档为准。

三、作用域:路径与通配符

作用域是 2.x 最锋利的安全工具。以 fs 插件为例:

{
  "identifier": "fs:scope",
  "allow": [
    { "path": "$APPDATA/**" },
    { "path": "$RESOURCE/config.json" }
  ],
  "deny": [
    { "path": "$APPDATA/secrets.db" }
  ]
}
变量 含义
$APPDATA 应用数据目录
$RESOURCE 打包资源目录
$DOCUMENT 用户文档目录
$DESKTOP 桌面

通配符 * 匹配单层路径,** 递归匹配多层。deny 优先于 allow,黑名单精确到单个文件,安全边界由此收紧。这套机制下,即便前端代码被注入恶意脚本,能操作的目录也被限制在声明范围内。

四、按窗口分配能力

多窗口应用可以为不同窗口下发不同能力。例如主窗口需要全量权限,预览窗口只需只读:

窗口 建议能力
主窗口 业务所需全部读写
设置窗口 配置目录读写
预览窗口 只读

做法是新增一份 Capability 文件,identifier 与 windows 对应。编译期会给每个窗口生成精确的白名单,运行时插件校验调用者身份。这是 Tauri 2.x 相对 1.x 最实质的进步,也是与 Electron 沙箱模型拉开差距的地方,架构背景见「Tauri 是什么:与 Electron 的架构对比」。

五、调试与常见错误

权限配错的典型表现是前端调用报权限相关错误,Rust 终端也会有对应提示。排查清单:

症状 检查点
前端报权限被拒 Capability 是否声明了该 permission
路径访问失败 scope 通配符是否覆盖目标路径
新窗口能力缺失 Capability 的 windows 是否包含该 label
编译报 schema 错 permission 名称拼写与插件版本

调试时可以先给宽松权限跑通,再逐步收紧,养成「最小权限」的迭代习惯。权限文件的管理与批量修改可以交给 AI 辅助,参考 Claude Code 指南;JSON 结构批量查找替换,正则 mastery 的正则技巧很实用;Rust 侧权限校验代码的阅读需要 Rust 入门 的基础。

六、权限设计清单

上线前用这份清单自查权限配置:

检查项 通过标准
无多余权限 删除任一权限应用仍编过但功能减少
scope 最小化 只声明真正访问的目录
deny 覆盖敏感文件 配置库、密钥文件显式 deny
窗口分级 公开窗口不持有管理能力
权限有文档 README 列出每条权限用途

还有一条进阶实践:把权限文件也纳入 code review 重点,像审查代码一样审查权限声明。权限是攻击面的直接刻画,一旦放宽容易默默背上风险。

Tauri 2.x 把权限做细,本质是把「信任前端多少」变成显式决策。每声明一条权限都问一句「这个窗口真的需要吗」,问完之后你的应用安全水位会明显高于行业平均。

权限模型是 Tauri 2.x 区别于 1.x 的核心,也是本系列最值得反复读的一章。建议团队里固定一个人 Review 权限变更,把每个新增 permission 的理由写进提交说明,半年后回看会很清楚能力边界是如何演化的。记住最小权限不是一次性的配置,而是随功能迭代持续维护的纪律。

多说一句权限演进的理念:Capability 模型让「每个窗口是一个能力面」成为现实。前端工程里我们习惯用路由与按钮控制可见性,Tauri 则把这套控制下沉到了系统能力层。这是安全设计上的一次范式转移,理解它比记住字段名重要得多——字段名会随版本变,范式会陪你走很远。

把权限模型放进更大的安全图景里看:Capability 管的是「前端能不能调」,系统级隔离、签名校验、CSP 各管一段。纵深防御的思想在 Tauri 2.x 里体现得非常完整,这也是它适合做商业级产品的原因之一。把每层职责想清楚,安全设计就从玄学变成了工程,这是本篇最希望你带走的东西。权限是本书体系里承上启下的一章:向下连接插件,向上连接打包发布,值得反复回看。

关于权限的日常维护再给一条具体做法:在项目根目录维护一份权限变更日志,每次新增或者调整 permission 时写一行记录,包含日期、窗口、权限名与理由。这份日志在年度安全审计、商店上架审核、新成员培训三个场景都能直接复用,成本几乎为零。权限这件事难点不在理解模型,而在长期执行的纪律性,一个小文件就能把这个软约束变成硬习惯,值得每个 Tauri 团队试试。

权限模型再从测试角度补一环:建议给关键权限写自动化验证。做法很简单,准备一组「应该成功」与「应该被拒绝」的调用清单,每次发版前跑一遍。权限回归是隐蔽的——重构某个插件版本可能悄悄弄丢了某条声明,自动化检查能在发版前拦住它。这套检查写得越早越省事,等项目大了再补会非常痛苦。

权限知识至此完整:模型是默认拒绝、声明才给;工具是 permission 与 scope;约束是 deny 优先于 allow;检验手段是 schema 校验与回归测试;长期靠变更日志与评审纪律。Tauri 2.x 把这套体系做成了产品级安全基座,用好它,你的应用在小体积之外还多一道纵深防线。带着这套认知往下读插件与打包两章,你会发现它们都围绕权限展开。

权限模型是全书里最值得反复阅读的一章,因为它定义了 Tauri 2.x 与其他桌面框架的本质区别。先记住默认拒绝四个字,其余的细节都能在实践中逐步补齐,带着问题回来查这份速查表效率最高。

延伸阅读

  • 官方插件清单:fs、dialog、shell 与 notification——能力声明的具体对象
  • tauri.conf.json 核心配置速查——配置体系的另一半
  • Rust 入门:理解权限在 Rust 侧的校验代码