从 Chrome 122 开始,适用于 Federated Credential Management API (FedCM) 的 Disconnect API 已推出。借助 Disconnect API,依赖方无需依赖第三方 Cookie,即可将其用户与身份提供方的账号断开关联。此外,FedCM 的同一网站处理方式也进行了一些更新。
Disconnect API
当用户通过身份联合在依赖方(RP,即使用身份提供商进行身份验证的网站)上创建账号时,身份提供商(IdP,即向其他方提供身份验证和账号信息的服务)通常会在其服务器上记录连接。通过存储的连接,IdP 可以跟踪用户已登录的 RP,并优化用户体验。例如,为了在用户日后返回 RP 时获得更好的体验,系统会将具有 IdP 的用户账号视为回访账号,从而支持自动重新身份验证和显示所用账号的个性化按钮等功能。
有时,IdP 会提供 API 来解除账号与 RP 的关联。不过,断开连接流程需要经过身份验证,并且需要 IdP Cookie。在没有第三方 Cookie 的世界中,当用户访问 RP 时,RP 无法使用浏览器 API 与 IdP 断开连接。由于同一 IdP 可能有多个账号与给定 RP 相关联,因此断开连接流程需要知道要断开连接的账号。
借助 Disconnect API,用户可以通过向指定端点发送信号,在浏览器和 IdP 服务器上将 IdP 账号与 RP 断开连接。用户需要使用联合凭据管理 API (FedCM) 完成身份联合。用户断开连接后,下次尝试使用 IdP 登录 RP 时,系统会将其视为新用户。
断开 IdP 与 RP 之间的连接
如果用户之前通过 FedCM 使用 IdP 登录了 RP,浏览器会在本地将该关系记忆为已关联账号的列表。RP 可以通过调用 IdentityCredential.disconnect()
函数来发起断开连接。此函数可从顶级 RP 帧调用。RP 需要传递 configURL
(它在 IdP 下使用的 clientId
)和 accountHint
,以便断开 IdP 的连接。账号提示可以是任意字符串,只要断开连接端点可以识别账号即可,例如电子邮件地址或用户 ID,该 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。
- 从不含 FedCM 权限政策的 iframe 中调用 API。
- config网址 无效或缺少断开连接端点。
- 内容安全政策 (CSP) 检查失败。
- 有一个待处理的解除关联请求。
- 用户已在浏览器设置中停用 FedCM。
当身份提供方的断开连接端点返回响应时,浏览器上的 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
。由于这两个网域是跨源且位于同一网站上,因此无法使用 Login Status API 将登录状态记录到浏览器。
通过这项变更,我们放宽了对 Login Status 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 响应标头设置登录状态。