权限可以从运行deno命令时获得。用户代码通常会假定自己拥有一组必需的权限,但是在执行过程中不能保证所授予的权限集将与此保持一致。
在某些情况下,确保容错程序需要一种在运行时与权限系统进行交互的方法。
权限描述符
在CLI上,的读取许可权/foo/bar
表示为 --allow-read=/foo/bar
。在运行时JS中,它表示如下:
const desc = { name: "read", path: "/foo/bar" } as const;
其他例子:
// Global write permission.
const desc1 = { name: "write" } as const;
// Write permission to `$PWD/foo/bar`.
const desc2 = { name: "write", path: "foo/bar" } as const;
// Global net permission.
const desc3 = { name: "net" } as const;
// Net permission to 127.0.0.1:8000.
const desc4 = { name: "net", host: "127.0.0.1:8000" } as const;
// High-resolution time permission.
const desc5 = { name: "hrtime" } as const;
查询权限
通过描述符检查是否授予许可。
// Global write permission.
const desc1 = { name: "write" } as const;
// Write permission to `$PWD/foo/bar`.
const desc2 = { name: "write", path: "foo/bar" } as const;
// Global net permission.
const desc3 = { name: "net" } as const;
// Net permission to 127.0.0.1:8000.
const desc4 = { name: "net", host: "127.0.0.1:8000" } as const;
// High-resolution time permission.
const desc5 = { name: "hrtime" } as const;
权限状态
权限状态可以是“已授予”,“提示”或“被拒绝”。从CLI授予的权限将查询到{ state: "granted" }
。{ state: "prompt" }
默认情况下未授予查询的那些查询,而 { state: "denied" }
保留给明确拒绝的查询。这将出现在“请求权限”中。
权限强度
对“查询”权限中第二个查询的结果的直观理解 是,授予了读取访问权限,/foo
并且/foo/bar
在该读取访问 权限之内,/foo
因此/foo/bar
允许对其进行读取。
我们也可以说,desc1
是 不是更强 desc2
。这意味着对于任何CLI授予的权限集:
- 如果有
desc1
疑问的{ state: "granted" }
话就必须如此desc2
。 - 如果有
desc2
疑问的{ state: "denied" }
话就必须如此desc1
。
更多示例:
const desc1 = { name: "write" } as const;
// is stronger than
const desc2 = { name: "write", path: "/foo" } as const;
const desc3 = { name: "net", host: "127.0.0.1" } as const;
// is stronger than
const desc4 = { name: "net", host: "127.0.0.1:8000" } as const;
请求权限
通过CLI提示符向用户请求未授权的权限。
// deno run main.ts
const desc1 = { name: "read", path: "/foo" } as const;
const status1 = await Deno.permissions.request(desc1);
// ⚠️ Deno requests read access to "/foo". Grant? [g/d (g = grant, d = deny)] g
console.log(status1);
// PermissionStatus { state: "granted" }
const desc2 = { name: "read", path: "/bar" } as const;
const status2 = await Deno.permissions.request(desc2);
// ⚠️ Deno requests read access to "/bar". Grant? [g/d (g = grant, d = deny)] d
console.log(status2);
// PermissionStatus { state: "denied" }
如果当前许可状态为“提示”,则提示将出现在用户终端上,询问他们是否要批准该请求。desc1
授予的请求, 因此将返回其新状态,并且将继续执行,就像--allow-read=/foo
在CLI上指定的一样。对的请求desc2
被拒绝,因此其许可状态从“提示”降为“拒绝”。
如果当前的权限状态已经是“已授予”或“已拒绝”,则请求的行为将类似于查询,并仅返回当前状态。这样既可以防止提示已授予的权限,也可以防止先前拒绝的请求。
撤消权限
将权限从“已授予”降级为“提示”。
// deno run --allow-read=/foo main.ts
const desc = { name: "read", path: "/foo" } as const;
console.log(await Deno.permissions.revoke(desc));
// PermissionStatus { state: "prompt" }
但是,当您尝试撤消仅属于CLI上授予的权限的一部分时,会发生什么情况?
// deno run --allow-read=/foo main.ts
const desc = { name: "read", path: "/foo/bar" } as const;
console.log(await Deno.permissions.revoke(desc));
// PermissionStatus { state: "granted" }
它没有被撤销。
要了解这种行为,可以想象Deno存储了一组内部的 显式授予的权限描述符。--allow-read=/foo,/bar
在CLI上指定时,将此设置初始化为:
[
{ name: "read", path: "/foo" },
{ name: "read", path: "/bar" },
];
授予运行时请求以{ name: "write", path: "/foo" }
将集合更新为:
[
{ name: "read", path: "/foo" },
{ name: "read", path: "/bar" },
{ name: "write", path: "/foo" },
];
Deno的权限撤销算法的工作原理是从该集中删除参数权限描述符比强大的所有元素。因此,为了确保 desc
不长批准,传递参数的描述符强于 任何一个明确授予的权限描述是要强 desc
。
// deno run --allow-read=/foo main.ts
const desc = { name: "read", path: "/foo/bar" } as const;
console.log(await Deno.permissions.revoke(desc)); // Insufficient.
// PermissionStatus { state: "granted" }
const strongDesc = { name: "read", path: "/foo" } as const;
await Deno.permissions.revoke(strongDesc); // Good.
console.log(await Deno.permissions.query(desc));
// PermissionStatus { state: "prompt" }