Copyright © 2024 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本规范定义了其他规范可以用来与浏览器权限交互的通用基础设施。这些权限代表用户对平台“强大功能”访问的允许或拒绝选择。对于开发人员来说,本规范标准化了一个API,用于查询强大功能的权限状态,并在使用强大功能的权限状态发生变化时接收通知。
本节描述了本文档在发布时的状态。当前W3C出版物列表及本技术报告的最新修订版本可在W3C技术报告索引中找到,网址为:https://www.w3.org/TR/。
本文档正在开发中。
本文档由Web应用程序安全工作组发布为工作草案,使用了推荐流程。
作为工作草案发布并不意味着W3C及其成员的认可。
本文档是草稿,可能随时被更新、替换或废弃。引用本文档时只能作为工作进展的参考。
本文档由在W3C专利政策下运作的小组制作。 W3C维护了与该小组交付物相关的任何专利披露的公开列表;该页面还包括专利披露的说明。任何知道其认为包含必要专利声明的个人必须按照W3C专利政策第6节披露信息。
本文档受2023年11月3日W3C流程文档管理。
本节为非规范性内容。
规范可以定义被明确标识为强大功能的特性。这些特性之所以被称为“强大”,是因为它们可能对隐私、安全性和性能产生重大影响。因此,用户依赖用户代理来拒绝网站使用这些特性,直到用户明确授予权限,并且通常仅限于授予一段有限的时间。允许网站使用强大功能的明确权限通常通过浏览器UI来授予和控制,如下图所示。
从这个意义上说,权限表示用户对某些类型功能,尤其是“强大功能”的当前同意状态。最终,用户保留这些权限的控制权,并有能力通过用户偏好手动授予或拒绝权限。此外,用户代理帮助用户管理权限,例如,隐藏和自动拒绝某些可能造成麻烦的权限提示,并在用户长时间未访问某个网站时自动使已授予的权限过期。
本节为非规范性内容。
本示例使用权限API决定是否通过地理位置API显示本地新闻,或提供一个按钮以添加该功能。
const { state } = await navigator.permissions.query({
name: "geolocation"
});
switch (state) {
case "granted":
showLocalNewsWithGeolocation();
break;
case "prompt":
showButtonToEnableLocalNews();
break;
case "denied":
showNationalNews();
break;
}
本示例同时检查"geolocation"
和"notifications"
强大功能的状态:
const queryPromises = ["geolocation", "notifications"].map(
name => navigator.permissions.query({ name })
);
for await (const status of queryPromises) {
console.log(`${status.name}: ${status.state}`);
}
本示例正在检查可用摄像头的权限状态。
const devices = await navigator.mediaDevices.enumerateDevices();
// 过滤视频输入,并映射到查询对象
const queries = devices
.filter(({ kind }) => kind === "videoinput")
.map(({ deviceId }) => ({ name: "camera", deviceId }));
const promises = queries.map((queryObj) =>
navigator.permissions.query(queryObj)
);
try {
const results = await Promise.all(promises);
// 记录每个摄像头的状态
results.forEach(({ state }, i) => console.log("摄像头", i, state));
} catch (error) {
console.error(error);
}
权限表示用户允许Web应用程序使用强大功能的决策。该决策以权限状态表示。
为了获取用户意图的新信息,用户代理可以收集并解释用户意图的信息。这些信息可以来自用户的明确操作、相关用户和其他用户的汇总行为,或本文档未预见的隐式信号。
每个权限都有一个生命周期,这是指特定权限保持"授予"状态的持续时间,直到恢复到其默认状态。生命周期可以是直到特定Realm被销毁、特定顶层浏览上下文被销毁、特定时间段或无限期。生命周期由最终用户和用户代理协商,当用户通过某些权限UI或用户代理定义的策略授予明确权限使用某个功能时,通常进行此协商。
用户代理维护一个权限存储,这是一个列表,包含权限存储条目。每个特定条目由其描述符和键表示,在该列表中最多只能出现一次。
权限存储条目是一个元组,由PermissionDescriptor
描述符、权限键的键和状态 状态组成。
要在给定PermissionDescriptor
描述符和权限键
键的情况下获取权限存储条目,请执行以下步骤:
要在给定PermissionDescriptor
描述符、一个权限键
键和一个状态 状态的情况下设置权限存储条目,请执行以下步骤:
权限键的类型由功能的权限键类型定义。
强大功能是用户在使用之前必须明确授予权限的Web平台功能(通常是API)。除了少数几个显著的例外(例如,通知API标准),大多数强大功能也是策略控制的功能。对于同时是策略控制的功能的强大功能,[Permissions-Policy]控制文档是否被允许使用某个功能。也就是说,只有在通过相应的策略控制的功能将权限委派给文档时,强大功能才能向用户请求明确权限。后续对功能的访问由用户"授予"权限或满足相当于权限授予的条件决定。
一个强大功能由其名称标识,即一个字符串字面量(例如,"geolocation")。
用户代理跟踪用户对哪些强大功能授予了权限,并通过环境设置对象管理这些权限。
每个强大功能可以定义零个或多个附加的方面。一个方面被定义为一个WebIDL字典,继承PermissionDescriptor
,并作为WebIDL接口的权限描述符类型。
当符合规范指定强大功能时,它:
PermissionDescriptor
。
在权限注册表中注册新指定的强大功能,为该工作组提供了反馈机会,并检查与本规范的集成是否有效。
PermissionDescriptor
或其子类型。如果未指定,默认值为PermissionDescriptor
。
该功能可以定义描述符实例的部分顺序。如果descriptorA强于descriptorB,则如果descriptorA的权限状态为"granted
",则descriptorB的权限状态也必须为"granted
",如果descriptorB的权限状态为"denied
",则descriptorA的权限状态也必须为"denied
"。
某些强大功能比仅仅提供一个PermissionState
关联了更多信息。这些功能中的每一个都定义了一个额外权限数据类型。
例如,getUserMedia
()
需要确定用户授权访问的是哪些摄像头。
如果 DOMString
name 指定了其中某个功能,那么 name 的
额外权限数据
针对可选的 环境设置对象
settings 的值由以下算法得出:
如果指定,则该额外权限数据算法可用于此功能。
PermissionStatus
或其子类型。如果未指定,默认值为PermissionStatus
。
接收一个权限描述符类型实例和一个新的或现有的权限结果类型实例,并更新权限结果类型实例的查询结果。由Permissions
的query
(permissionDesc)
方法和PermissionStatus
更新步骤使用。如果未指定,默认使用默认权限查询算法。
默认权限查询算法,给定一个PermissionDescriptor
permissionDesc和一个PermissionStatus
status,运行以下步骤:
接收一个环境设置对象, 并返回一个新的权限键。如果未指定,则默认使用默认权限键生成算法。指定自定义权限键生成算法的功能必须还指定一个权限键比较算法。
不接收任何参数。更新实现中的其他部分,使其与权限状态或额外权限数据的变化保持同步。
如果未指定,默认运行响应用户撤销权限。
定义一个或多个强大功能的规范应该建议最适合特定功能的权限生命周期。 以下提供了一些确定权限生命周期的指南,重点是用户隐私。如果未指定生命周期,则由用户代理提供。
当来源的权限生命周期到期时:
一个PermissionState
值,用作权限的默认状态,适用于强大功能。
要获取当前权限状态,给定一个名称 name 和一个可选的
环境设置对象
settings,执行以下步骤。该算法返回一个
PermissionState
枚举值。
PermissionDescriptor
,其
name
被初始化为
name。
描述符的权限状态,给定一个可选的
环境设置对象
settings,结果如下算法所示。它返回一个
PermissionState
枚举值:
denied
"。
name
。
文档
,则执行以下步骤:
PermissionState
枚举值来自entry的
状态。
PermissionState
枚举值,考虑到任何描述符的
权限状态限制。
简写形式为,DOMString
的name的权限状态是
权限状态,
PermissionDescriptor
带有其
name
成员设为name。
要请求使用权限一个描述符,用户代理必须执行以下步骤。
该算法返回"granted
"或"denied
"。
prompt
",
返回current state并中止这些步骤。
granted
";否则设置为
"denied
"。
用户的交互可能会为用户意图的新信息提供输入,
用于该来源。
该操作故意对权限UI的细节以及用户代理如何推断用户意图保持模糊。用户代理应能够在此框架内探索大量UI选项。
简写形式为请求使用权限一个
DOMString
name,
相当于请求使用权限一个
PermissionDescriptor
,
其中name
成员设置为name。
要提示用户选择与给定
描述符相关的一个或多个选项,以及一个可选的布尔值
allowMultiple(默认为false),用户代理必须执行以下步骤。该算法返回
"denied
"或用户的选择。
denied
",
则返回"denied
"并中止这些步骤。
granted
",用户代理可以返回用户选择的一个(或多个,如果
allowMultiple为true)选项,并中止这些步骤。如果用户代理在不提示的情况下返回,
则后续对相同描述符和相同选项集的提示必须返回相同的选项,
除非用户代理收到了有关用户意图的新信息。
denied
"。
该操作故意对权限UI的细节以及用户代理如何推断用户意图保持模糊。用户代理应能够在此框架内探索大量UI选项 (例如,权限提示可能会超时并自动返回"denied",而无需用户明确选择)。
简写形式为提示用户选择与
DOMString
name相关的选项,
相当于提示用户选择与
PermissionDescriptor
相关的选项,其中name
成员设置为name。
当用户代理得知用户不再打算授予使用描述符中描述的功能的权限,并且该功能是在由
PermissionDescriptor
中的key描述的上下文中时,通过执行以下步骤对用户撤销权限的操作:
WebIDL[Exposed=(Window,Worker)]
interface Permissions
{
Promise<PermissionStatus
> query
(object permissionDesc);
};
dictionary PermissionDescriptor
{
required DOMString name
;
};
当 query()
方法被调用时,用户代理 必须 运行以下
查询权限 算法,传递参数 permissionDesc:
Window
对象,则:
Document
不是
完全活动,则返回
一个被拒绝的
promise,并带有
"InvalidStateError
"
DOMException
。
PermissionDescriptor
。
name
"]
不被支持,则返回 一个被拒绝的 promise,并带有 TypeError
。
name
的 权限描述符类型。
PermissionStatus
。
[[query]]
内部插槽。
name
的 权限查询算法,并传递
query 和 status。
WebIDL[Exposed=(Window,Worker)]
interface PermissionStatus
: EventTarget {
readonly attribute PermissionState
state
;
readonly attribute DOMString name
;
attribute EventHandler onchange
;
};
enum PermissionState
{
"granted
",
"denied
",
"prompt
",
};
PermissionStatus
实例会创建一个
[[query]] 内部槽,
它是某个特性的 权限描述符类型 的实例。
"granted
"、"denied
" 和
"prompt
" 枚举值分别表示 "授予"、"拒绝" 和
"提示" 的概念。
name
属性返回其初始化的值。
state
属性返回在当前实例上设置的最新值。
onchange
属性是一个 事件处理程序,其对应的
事件类型
是
change
。
每当 用户代理 知道
PermissionStatus
实例 status 的状态已更改时,它将异步运行 PermissionStatus
更新步骤:
如果 PermissionStatus
对象有类型为
change
的
事件监听器,
则 不得 将其进行垃圾回收。
除了标记为非规范的部分外,本规范中的所有创作指南、图表、示例和注释均为非规范内容。本规范中的其他内容均为规范性内容。
本文件中的关键词 MAY、MUST、MUST NOT、OPTIONAL 和 SHOULD 应按照 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释,仅当它们以全大写形式出现时,如本处所示。
本节为非规范性内容。
尽管本规范与 权限策略 规范都涉及“权限”,但每个规范在平台中都有独特的作用。 尽管如此,这两个规范确实存在明确的重叠。
一方面,本规范只关心通过用户代理权限UI管理访问的 强大功能 (即,用户在使用该功能前给予明确同意,并且用户可以随时以任何理由拒绝该权限的权限),这些强大功能已在 权限注册表 中注册。
另一方面,权限策略 规范允许开发人员通过“权限策略”
(无论是 HTTP 头还是
allow
属性)选择性地启用和禁用策略控制的功能。
从这个意义上说,权限策略包含了本规范,因为 权限策略 规范决定功能是否可用,而与本规范无关。
这些策略控制的功能也在 权限注册表 中注册。
被 权限策略 禁用的强大功能在本规范中总是反映为 权限状态 为“denied”。 这是因为 读取当前权限状态 依赖于 [HTML] 中的“允许使用”检查, 该检查本身调用了 权限策略 规范。 这里需要注意的是在两个规范中共享权限名称。本规范和 权限策略 规范都依赖于其他规范来定义权限名称, 并且它们通常名称相同(例如,地理定位 API 中的“geolocation”等)。
最后,通过 权限策略 规范,强大功能永远不可能被授予“granted”状态。 强大功能被 “授予” 的唯一方法是通过用户明确的权限或某些用户代理策略。
为了用户代理自动化和应用程序测试的目的,本文档定义了对 [WebDriver] 和 [WebDriver-BiDi] 规范的扩展。用户代理支持它们是可选的。
WebIDLdictionary PermissionSetParameters
{
required object descriptor
;
required PermissionState
state
;
};
为给定的 PermissionDescriptor
descriptor、PermissionState
state、一个可选的 origin 和一个可选的
user agent 设置权限时:
本文档定义了 [WebDriver] 规范的以下 扩展命令。
HTTP 方法 | URI 模板 |
---|---|
POST | /session/{session id}/permissions |
设置权限 扩展命令模拟用户修改 PermissionDescriptor
的 权限状态。
远程端步骤如下:
PermissionSetParameters
的 IDL
值。如果抛出异常,返回 无效参数 错误。
state
是由于任何实现定义的原因而导致的不适当的 权限状态,则返回 无效参数 错误。
descriptor
。
name
")
结果匹配的 权限描述符类型的 IDL
值。如果此转换抛出异常,返回 无效参数 错误。
state
。
null
。
本文档为 [WebDriver-BiDi] 规范定义了以下 扩展模块。
权限模块包含管理远程端浏览器权限的命令。
PermissionsCommand = (
permissions.setPermission
)
permissions.PermissionDescriptor = {
name: text,
}
permissions.PermissionDescriptor
类型表示 PermissionDescriptor
。
permissions.PermissionState = "granted" / "denied" / "prompt"
permissions.PermissionState
类型表示 PermissionState
。
Set Permission 命令 模拟用户修改 PermissionDescriptor
的 permission state。
permissions.setPermission = (
method: "permissions.setPermission",
params: permissions.SetPermissionParameters
)
permissions.SetPermissionParameters = {
descriptor: permissions.PermissionDescriptor,
state: permissions.PermissionState,
origin: text,
? userContext: text,
}
EmptyResult
远程端步骤 与 session 和 command parameters 如下:
descriptor
字段的值。
name
字段的值,代表 name
。
state
字段的值。
userContext
字段的值(如果存在),否则为 default
。
origin
字段的值。
null
的 成功。
本节为非规范性内容。
本W3C 注册表提供了一个集中的地方,用于查找 Web 平台的 策略控制功能 和/或 强大功能。 通过 更改过程,该注册表还确保了平台中的权限在各种规范中得到一致的规定。
通过将注册表划分为标准化权限和临时权限,注册表还提供了一种方法来跟踪这些功能的状态。
本更改过程 用于添加或更新此注册表,步骤如下:
要使某个权限出现在标准化权限表中,并被认为是 标准化权限,需要满足以下标准:
每个 权限 由一个唯一的字面字符串标识。 对于 权限策略,该字符串标识的是 策略控制功能。 同样,在 权限 规范中,该字符串标识的是 强大功能。
标识字符串 | 是否为 策略控制功能? | 是否为 强大功能? | 规范 | 实现情况 | ||
---|---|---|---|---|---|---|
Chromium | Gecko | WebKit | ||||
"geolocation" | 是 | 是 | Geolocation API | 是 | 是 | 是 |
"notifications" | 否 | 是 | Notifications API Standard | 是 | 是 | 是 |
"push" | 否 | 是 | Push API | 是 | 是 | 是 |
"web-share" | 是 | 否 | Web Share API | 是 | 是 | 是 |
临时权限是尚未 标准化 的权限 (即它们要么是实验性的,还处于孵化阶段,或者仅在单一浏览器引擎中实现)。
标识字符串 | 是否为 策略控制功能? | 是否为 强大功能? | 规范 | 实现情况 | ||
---|---|---|---|---|---|---|
Chromium | Gecko | WebKit | ||||
"accelerometer" | 是 | 是 | DeviceOrientation 事件规范 | 是 | 否 | 否 |
"window-management" | 是 | 是 | 窗口管理 | 是 | 否 | 否 |
"local-fonts" | 是 | 是 | 本地字体访问 | 是 | 否 | 否 |
对手可能会利用权限状态作为创建用户“指纹”的元素。虽然对手已经可以通过实际使用 API 来确定权限状态,但这通常会导致向终端用户显示 UI 提示(如果权限尚未被“授予”)。虽然该 API 不会向网站暴露新的指纹信息,但它使对手更容易悄悄地访问这些信息。
目前没有记录的安全注意事项。建议读者参考第D. 隐私注意事项部分。
WebIDL[Exposed=(Window)]
partial interface Navigator {
[SameObject] readonly attribute Permissions
permissions
;
};
[Exposed=(Worker)]
partial interface WorkerNavigator {
[SameObject] readonly attribute Permissions
permissions
;
};
[Exposed=(Window,Worker)]
interface Permissions
{
Promise<PermissionStatus
> query
(object permissionDesc);
};
dictionary PermissionDescriptor
{
required DOMString name
;
};
[Exposed=(Window,Worker)]
interface PermissionStatus
: EventTarget {
readonly attribute PermissionState
state
;
readonly attribute DOMString name
;
attribute EventHandler onchange
;
};
enum PermissionState
{
"granted
",
"denied
",
"prompt
",
};
dictionary PermissionSetParameters
{
required object descriptor
;
required PermissionState
state
;
};
本节为非规范性部分。
编辑们感谢 Adrienne Porter Felt、Anne van Kesteren、Domenic Denicola、Jake Archibald 和 Wendy Seltzer 对 API 设计和编辑工作的帮助。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: