HoppScotch Desktop 中 tauri-plugin-relay 的 Tauri 权限体系解析:relay 命令的授权与管控
【免费下载链接】hoppscotchOpen-Source API Development Ecosystem • https://hoppscotch.io • Offline, On-Prem & Cloud • Web, Desktop & CLI • Open-Source Alternative to Postman, Insomnia项目地址: https://gitcode.com/GitHub_Trending/ho/hoppscotch
本文以 HoppScotch 桌面端内嵌的tauri-plugin-relay插件自动生成的权限参考文档为核心,完整梳理relay:allow-execute、relay:allow-cancel、relay:allow-run、relay:allow-subscribe等权限标识符的含义与来源,并结合插件源码(lib.rs、commands.rs、guest-js/index.ts)与桌面端 capability 配置(src-tauri/capabilities/default.json),说明 Tauri 2.0 的 allow/deny 权限模型如何落到一次真实的 HTTP 请求调用链上。读完本文,你可以理解该插件默认开放了哪些能力、如何按需收紧或扩展权限,以及权限标识符与 Rust 命令、前端 invoke 调用之间的精确对应关系。
一、tauri-plugin-relay:权限体系的服务对象
tauri-plugin-relay是位于 packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay 的 Tauri 插件,其 README.md 将其描述为"A HTTP request-response relay plugin for Tauri apps",用于把 HTTP 请求转发到系统原生网络栈(基于 libcurl 的relaycrate)执行,从而绕开浏览器的 CORS 与 Fetch 限制,支持证书管理、代理、多种认证方式与可取消的异步请求。
该插件在仓库中处于两个位置:
- 插件工作区副本:plugin-workspace/tauri-plugin-relay,包含完整的权限定义、Rust 侧实现与 guest JS SDK;
- 宿主应用引用:HoppScotch 桌面端通过 src-tauri/Cargo.toml 以固定 git revision 的方式依赖该插件,即
tauri-plugin-relay = { git = "https://github.com/CuriousCorrelation/tauri-plugin-relay", rev = "273488c8..." },工作区副本用于对齐与二次开发。
从 Cargo.toml 可见其核心依赖:tauri 2.1.0、tauri-plugin 2.5.4(build feature)以及底层relaycrate。插件要求 Rust 1.77.2+,对应 package.json 中的 npm 包名为@CuriousCorrelation/plugin-relay(0.1.0,依赖@tauri-apps/api 2.1.1)。理解这些背景后,本文的权限参考文档就有了明确的上下文:权限标识符管控的正是插件暴露给 WebView 的那组 IPC 命令。
二、权限参考文档(reference.md)完整解读
权限参考文档位于 permissions/autogenerated/reference.md,由 Tauri 插件构建体系从各命令的权限定义自动生成。其内容包含两个部分:默认权限集与完整权限表。
2.1 Default Permission(默认权限集)
文档开头声明:
Default permissions for the plugin This default permission set includes the following:
allow-executeallow-cancel
即插件的relay:default权限别名只包含两项:allow-execute与allow-cancel。这一点与 permissions/default.toml 的机器可读定义完全一致:
[default] description = "Default permissions for the plugin" permissions = ["allow-execute", "allow-cancel"]这个设计意图很清晰:插件对外暴露的核心能力是"执行请求"(execute)与"取消请求"(cancel),两者构成最小可用的请求生命周期管理;其余命令(run、subscribe)不属于默认开放范围,需要应用显式声明。
2.2 Permission Table(完整权限表)
文档中的权限表逐一列出了 8 个权限标识符,以下完整继承原文档内容并补充其机制说明:
| Identifier | Description(原文描述) |
|---|---|
relay:allow-cancel | Enables the cancel command without any pre-configured scope. |
relay:deny-cancel | Denies the cancel command without any pre-configured scope. |
relay:allow-execute | Enables the execute command without any pre-configured scope. |
relay:deny-execute | Denies the execute command without any pre-configured scope. |
relay:allow-run | Enables the run command without any pre-configured scope. |
relay:deny-run | Denies the run command without any pre-configured scope. |
relay:allow-subscribe | Enables the subscribe command without any pre-configured scope. |
relay:deny-subscribe | Denies the subscribe command without any pre-configured scope. |
表格遵循 Tauri 权限系统的标准命名约定:
relay:前缀:插件在 src/lib.rs 中通过Builder::new("relay")注册的插件名,权限标识符统一形如relay:<permission>;allow-X/deny-X成对出现:每个 IPC 命令(execute、cancel、run、subscribe)都生成一对允许与拒绝权限,分别映射到commands.allow与commands.deny列表(见下文 3.1 节);- "without any pre-configured scope":这 4 个命令都不带 scope 参数,因此权限不携带作用域,授权即全量放行对应命令。
值得注意的是,allow-run/allow-subscribe出现在权限表中,但在 HoppScotch 桌面端实际使用的插件版本里,Rust 侧 lib.rs 的invoke_handler目前只注册了commands::execute与commands::cancel两个命令:
Builder::new("relay") .invoke_handler(tauri::generate_handler![ commands::execute, commands::cancel ])从源码结构看,run与subscribe的权限条目已随权限系统生成并保留,可以推断它们是为后续将要开放或已在上游演进的命令预留的授权位——即便应用提前声明了relay:allow-run,在当前注册的命令集合下也没有对应的可调用入口。这正是"权限先于命令开放"的保守设计:授权体系先行铺好,命令随时可挂接。
三、权限是怎么生成的:autogenerated 目录的机器可读定义
permissions/autogenerated/目录下的每个命令权限都有对应的 TOML 定义文件,且文件头均标注# Automatically generated - DO NOT EDIT!,即由tauri-plugin的 build 依赖(见 Cargo.toml 中[build-dependencies] tauri-plugin = { version = "2.5.4", features = ["build"] })在编译期生成,reference.md是面向人的汇总视图。
3.1 单个命令的权限定义结构
以 permissions/autogenerated/commands/execute.toml 为例:
# Automatically generated - DO NOT EDIT! "$schema" = "../../schemas/schema.json" [[permission]] identifier = "allow-execute" description = "Enables the execute command without any pre-configured scope." commands.allow = ["execute"] [[permission]] identifier = "deny-execute" description = "Denies the execute command without any pre-configured scope." commands.deny = ["execute"]结构要点:
"$schema"指向权限 JSON Schema:permissions/schemas/schema.json 是校验文件,Tauri 在构建时用它校验宿主应用的 capability 配置,写错权限名会在编译期/启动期报错而非静默失效;- 一个 TOML 生成一对权限:
[[permission]]块按identifier分别定义 allow 与 deny 两个条目,commands.allow/commands.deny中列出被管控的命令名(这里是裸命令名execute,解析时会结合插件前缀变成plugin:relay|execute); - 其余三个命令文件结构完全相同:cancel.toml、run.toml、subscribe.toml 分别管控
cancel、run、subscribe命令,生成 2×4 = 8 个权限标识符,与 reference.md 权限表逐条对应。
这套机制意味着:要新增一条可被权限管控的命令,只需在 Rust 侧添加#[command]函数并注册进invoke_handler,构建系统会自动产出对应的allow-xxx/deny-xxx权限与文档,宿主应用无需修改插件代码即可获得最小权限控制点。
四、默认权限的生效路径:从 default.toml 到桌面端 capability
relay:default这个别名如何被 HoppScotch 桌面端使用?链路如下:
- permissions/default.toml定义别名
default→["allow-execute", "allow-cancel"]; - 构建期生成权限 schema 后,宿主应用即可在 capability 中引用
relay:default; - HoppScotch 桌面端的 src-tauri/capabilities/default.json 在主 capability 中声明了
"relay:default"(与core:default、shell:allow-open、appload:default等并列):
{ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "Capability for the main window and all app:// origins", "windows": ["*"], "webviews": ["*"], "remote": { "urls": ["app://*"] }, "permissions": [ "core:default", ... "appload:default", "relay:default" ] }该 capability 的作用域是"windows": ["*"]、"webviews": ["*"]且远程 URL 限定为app://*,因此插件 WebView 内所有来自应用来源的 JS 都可以调用relay:default所覆盖的execute与cancel。而run、subscribe未包含在relay:default中——如果未来开放了这些命令,应用必须另行显式加入relay:allow-run/relay:allow-subscribe才能调用,默认状态是拒绝的。
这里体现了 Tauri 权限体系的deny-by-default原则:未在任何 capability 中出现的命令一律不可调用;default只是插件方提供的"合理最小集"约定,而非强制。
五、权限标识符与真实命令的对应关系
把 reference.md 中的权限表放到真实调用链上看,每个权限守护的是哪段代码?
5.1 execute:权限 → Rust 命令 → relay crate
前端入口:guest-js/index.ts 中的 SDK 函数通过 Tauri invoke 调用命令,
relay:allow-execute守护的正是这条通道:export async function execute(request: Request): Promise<RequestResult> { return await invoke<RequestResult>('plugin:relay|execute', { request }) }注意 invoke 通道名
plugin:relay|execute:插件名(relay)与裸命令名(execute,即 TOML 中commands.allow = ["execute"]的取值)拼接而成,与权限定义中的命令名严格一致。Rust 命令:src/commands.rs 中
#[command] pub(crate) async fn execute(...)接收RunRequest,经app.relay().execute(request)执行并返回ExecuteResponse(Success/Error 两态),全程带 tracing 日志;平台实现:src/desktop.rs 的
Relay<R>::execute调用底层relay::execute(request).await——即独立relaycrate 中的 libcurl 实现;移动端走#[cfg(mobile)]分支(src/mobile.rs),但 IPC 命令与权限模型不变。
Request类型在 guest-js 中定义了完整的请求能力面:id/url/method/version、headers/params、content(text/json/xml/form/binary/multipart/urlencoded/stream 八种)、auth(none/basic/bearer/digest/oauth2/apikey/aws 七种)、security(客户端证书 PEM/PFX、CA 证书、verifyHost、verifyPeer)、proxy(含代理认证)以及options(timeout、followRedirects、maxRedirects、decompress、cookies、keepAlive)。这些正是"无需 scope 的 execute 权限"所放行的能力全集——因此收紧 execute 权限只能整条放行或整条拒绝。
5.2 cancel:与 execute 配对的取消通道
relay:allow-cancel守护plugin:relay|cancel通道:
export async function cancel(requestId: number): Promise<void> { return await invoke<void>('plugin:relay|cancel', { requestId }) }Rust 侧 commands.rs 的cancel命令接收CancelRequest(携带请求id),经 desktop.rs 转发到relay::cancel(request_id),实现对在途 libcurl 请求的取消——这与 README.md 中 "Async request execution with cancellation support" 的特性描述吻合。cancel与execute一并进入默认权限集,正是为了保证"可取消"这一核心 UX 不因权限裁剪而缺失。
5.3 run / subscribe:已生成、待开放的权限位
如第二节所述,run与subscribe命令未在当前版本invoke_handler中注册,其权限条目属于预生成状态。从权限表的描述格式("Enables the run command without any pre-configured scope")可以确认,将来开放时同样遵循无 scope 模型,应用侧只需在 capability 中追加relay:allow-run或relay:allow-subscribe即可。桌面端前端对 relay 的引用也印证了当前命令面:src/kernel/relay.ts 通过 kernel 模块机制导出Relay,是应用侧消费该插件的封装入口。
六、如何在自己的 Tauri 应用中配置 relay 权限
基于上述机制,宿主应用对 relay 权限的控制手段可以归纳为三种典型写法(均写在应用的 capability 文件中,而非修改插件本身):
- 采纳默认集(HoppScotch 的做法):
permissions中加入"relay:default",获得 execute + cancel; - 最小权限/禁用:不声明任何
relay:*权限——deny-by-default 使所有命令不可用;如需在已声明relay:default的 capability 中显式收回某命令,加入对应 deny 权限,例如"relay:deny-execute",Tauri 的解析顺序中 deny 优先于 allow; - 扩展开放:待
run/subscribe命令开放后,按需追加"relay:allow-run"等条目,同时可用"relay:deny-subscribe"保留关闭。
由于权限文件都经过 schemas/schema.json 校验,任何拼写错误的标识符都会在建构阶段暴露;生成产物(commands/*.toml与reference.md)标注了DO NOT EDIT,权限面调整应通过上游命令定义驱动重新生成,而非手改文档。
七、小结
tauri-plugin-relay的权限参考文档虽然篇幅不大,但它是一个完整的 Tauri 2.0 插件权限样本:
- 默认集
relay:default = [allow-execute, allow-cancel],对应插件最小可用的"发请求 + 取消请求"能力面,由 default.toml 机器可读定义; - 8 个权限标识符(execute/cancel/run/subscribe 各自的 allow/deny)由 autogenerated/commands/*.toml 在构建期生成,
reference.md是它们的汇总视图; - 权限 → 命令 → 实现的对应关系清晰可查:capability 中的
relay:allow-execute放行plugin:relay|executeinvoke 通道,落到 commands.rs 的execute命令,最终由relaycrate 的 libcurl 栈执行; - HoppScotch 桌面端通过 capabilities/default.json 仅声明
relay:default,run/subscribe保持未开放状态,体现了"权限预留、命令按需开放"的演进策略。
进一步深入时,可依次阅读:插件 README(能力总览)、guest-js/index.ts(前端类型定义全集)、src/lib.rs(插件装配与平台分发),以及同工作区内的 relay crate 源码(认证、证书、代理、内容处理的具体实现)。
【免费下载链接】hoppscotchOpen-Source API Development Ecosystem • https://hoppscotch.io • Offline, On-Prem & Cloud • Web, Desktop & CLI • Open-Source Alternative to Postman, Insomnia项目地址: https://gitcode.com/GitHub_Trending/ho/hoppscotch
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考