从 Chrome 122 开始,可使用 Federated Credential Management API (FedCM) 的 Disconnect API。借助 Disconnect API,依赖方无需依赖第三方 Cookie 即可将其用户与身份提供方帐号断开连接。此外,FedCM 的同网站处理机制也进行了一些更新。
断开 API 连接
当用户通过身份联合在依赖方(RP,即使用身份提供方进行身份验证的网站)上创建帐号时,身份提供方(IdP - 向其他方提供身份验证和帐号信息的服务)通常会在其服务器上记录连接。通过存储的连接,IdP 可以跟踪用户已登录的 RP,并优化其体验。例如,为了在用户稍后返回 RP 时提供更好的体验,具有 IdP 的用户帐号将被视为返回帐号,这样就可以启用自动重新身份验证和显示所用帐号的个性化按钮等功能。
有时,IdP 会提供 API 来取消帐号与 RP 的关联。但是,断开连接流程需要进行身份验证,并且需要 IdP Cookie。在没有第三方 Cookie 的情况下,当用户访问 RP 时,不存在可让 RP 与 IdP 断开连接的浏览器 API。由于可能有多个来自同一 IdP 的 IdP 帐号与给定 RP 相关联,因此断开连接流程需要知道哪个帐号正在断开连接。
借助 Disconnect API,用户可通过向指定端点发送信号来断开 IdP 帐号与浏览器和 IdP 服务器上 RP 的连接。用户需要使用 Federated Credential Management API (FedCM) 完成身份联合。用户断开连接后,当用户下次尝试使用 IdP 登录 RP 时,系统会将其视为新用户。
断开 IdP 与 RP 的连接
如果用户之前已通过 FedCM 使用 IdP 登录 RP,浏览器会将这种关系在本地记忆为已关联帐号的列表。RP 可以通过调用 IdentityCredential.disconnect()
函数发起断开连接。可以从顶级 RP 帧调用此函数。RP 需要传递 configURL
、其在 IdP 下使用的 clientId
以及 accountHint
,以便 IdP 断开连接。帐号提示可以是任意字符串,前提是断开连接端点可以识别帐号,例如电子邮件地址或用户 ID,其不一定与帐号列表端点提供的帐号 ID 一致:
// Disconnect an IdP account "account456" from the RP "https://idp.com/". This is invoked on the RP domain.
IdentityCredential.disconnect({
configURL: "https://idp.com/config.json",
clientId: "rp123",
accountHint: "account456"
});
IdentityCredential.disconnect()
会返回 Promise
。此 promise 可能会由于以下原因抛出异常:
- 用户未通过 FedCM 使用 IdP 登录 RP。
- 此 API 是从没有 FedCM 权限政策的 iframe 中调用的。
- config网址 无效或缺少断开连接端点。
- 内容安全政策 (CSP) 检查失败。
- 有一个待处理的断开连接请求。
- 用户在浏览器设置中停用了 FedCM。
当 IdP 的断开连接端点返回响应时,RP 和 IdP 在浏览器中会断开连接,并且 promise 得到解析。断开连接的用户帐号在来自断开连接端点的响应中指定。
设置 IdP 配置文件
为了支持 Disconnect API,IdP 必须支持断开连接端点,并在其 IdP 配置文件中提供 disconnect_endpoint
属性及其路径。
{
"accounts_endpoint": "/accounts",
"id_assertion_endpoint": "/assertion",
...
"disconnect_endpoint: "/disconnect"
}
在断开连接端点上断开账号连接
通过调用 IdentityCredential.disconnect()
,浏览器会向此断开连接端点发送一个包含 Cookie 和内容类型 application/x-www-form-urlencoded
的跨源 POST
请求,其中包含以下信息:
媒体资源 | 说明 |
---|---|
account_hint |
关于 IdP 账号的提示。 |
client_id |
RP 的客户端标识符。 |
POST /disconnect HTTP/1.1
Host: idp.example
Origin: rp.example
Content-Type: application/x-www-form-urlencoded
Cookie: 0x123
Sec-Fetch-Dest: webidentity
account_hint=account456&client_id=rp123
收到请求后,IdP 服务器应该:
- 使用 CORS(跨域资源共享)响应请求。
- 验证请求是否包含
Sec-Fetch-Dest: webidentity
HTTP 标头。 - 将
Origin
标头与由client_id
确定的 RP 源进行匹配。如果不匹配,则拒绝。 - 找到与
account_hint
匹配的帐号。 - 从 RP 的关联账号列表中断开用户账号。
- 以 JSON 格式使用已识别用户的
account_id
响应浏览器。
响应 JSON 载荷示例如下所示:
{
"account_id": "account456"
}
如果 IdP 希望浏览器断开与 RP 关联的所有帐号的关联,请传递一个与任何帐号 ID 都不匹配的字符串,例如 "*"
。
现在,当 RP 和 IdP 为同一网站时,系统会跳过检查 /.well-known/web-identity
在开发 FedCM 系统时,测试或预演 RP 服务器网域可能是生产 IdP 服务器的子网域。例如,生产 IdP 服务器位于 idp.example
,预演 RP 服务器和预演 IdP 服务器均位于 staging.idp.example
。但是,由于众所周知的文件必须放置在 IdP 服务器的 eTLD+1 的根目录下,因此它必须位于 idp.example/.well-known/web-identity
并且是生产服务器。在开发过程中,开发者不一定能将文件放入生产环境中,因此这导致他们无法测试 FedCM。
从 Chrome 122 开始,如果 RP 网域和 IdP 网域相同,Chrome 会跳过检查已知文件。这样一来,开发者便能够在这种情况下进行测试。
子资源现在可以设置同网站登录状态
以前,Chrome 只允许在请求所有祖先实体同源时设置登录状态(例如,使用 Set-Login: logged-in
标头)。这样可以阻止通过同网站
fetch()
请求设置登录状态。
例如,假设有个网站允许用户在 idp.example
上输入其用户名和密码,但凭据会通过 fetch()
发布到 login.idp.example
。无法使用 LoginStatus API 记录浏览器的登录状态,因为这两个网域是跨源网域和同网站网域。
进行此更改后,我们放宽了对 LoginStatus API 与所有祖先实体同网站的要求,并使上述示例能够使用 HTTP 标头 (Set-Login:
logged-in
) 设置 login.idp.example
的登录状态。
摘要
通过使用 Disconnect API,FedCM 现在可以断开 RP 与 IdP 的连接,而无需依赖第三方 Cookie。为此,请在 RP 上调用 IdentityCredential.disconnect()
。借助此函数,浏览器会向 IdP 的断开连接端点发送请求,以便 IdP 能够终止服务器上的连接,然后再终止浏览器上的连接。
我们已宣布,出于测试目的,当 RP 和 IdP 为同一网站时,系统会跳过 /.well-known/web-identity
检查。此外,现在还可以通过来自同网站 IdP 子资源的 HTTP 响应标头设置登录状态。