调用 get() 方法
RP 可以调用 navigator.credentials.get() 并带有 identity 选项,以请求用户获得使用现有 IdP 账户(他们在浏览器中已登录的账户)登录 RP 的选项。IdP 通过其 clientId 识别 RP,该 clientId 由每个 IdP 通过单独的 IdP 特定过程颁发给 RP。所选的 IdP 会识别在登录流程中通过提供给浏览器的凭据(Cookie)尝试登录的特定用户。
如果所选 IdP 成功验证了用户身份,该方法将返回一个 Promise,该 Promise 将解析为 IdentityCredential 对象。此对象包含一个令牌,其中包含已用 IdP 的数字证书签名的用户身份信息。
RP 将令牌发送到其服务器以验证证书,成功后可以使用令牌中(现在受信任的)身份信息将其登录到其服务(开始新会话),如果他们是新用户,则将其注册到其服务,等等。
如果用户从未登录 IdP 或已注销,则 get() 方法将因错误而拒绝,并且 RP 可以将用户引导至 IdP 页面以登录或创建账户。
注意:验证令牌的确切结构和内容对 FedCM API 和浏览器而言是透明的。IdP 决定其语法和用法,RP 需要遵循 IdP 提供的说明(例如,请参阅在您的服务器端验证 Google ID 令牌),以确保正确使用它。
一个典型的请求可能如下所示:
async function signIn() {
const identityCredential = await navigator.credentials.get({
identity: {
context: "signup",
providers: [
{
configURL: "https://accounts.idp.example/config.json",
clientId: "********",
nonce: "******",
loginHint: "user1@example.com",
},
{
// ...
},
],
},
});
}
identity.providers 属性接受一个数组,其中包含一个或多个对象,指定每个 IdP 配置文件(configURL)的路径和 IdP 颁发给 RP 的客户端标识符(clientId)。
前面的示例还包含一些可选功能
identity.context指定用户通过 FedCM 进行身份验证的上下文。例如,是该账户的首次注册,还是使用现有账户登录?浏览器使用此信息来改变其 FedCM UI 中的文本,以更好地适应上下文。nonce属性提供一个随机 nonce 值,该值确保响应是为此特定请求发出的,从而防止重放攻击。loginHint属性提供关于浏览器应为用户登录显示的账户选项的提示。此提示与 IdP 在账户列表端点提供的login_hints值匹配。
浏览器请求 IdP 配置文件并执行下面详述的登录流程。有关用户可能期望的浏览器提供的 UI 交互类型的更多信息,请参阅 使用身份提供商登录信赖方。
FedCM 登录流程
登录流程涉及三方——RP 应用程序、浏览器本身和 IdP。下图直观地总结了正在发生的事情。

流程如下:
-
RP 调用
navigator.credentials.get()以启动登录流程。 -
根据每个 IdP 提供的
configURL,浏览器请求两个文件:- 众所周知的文件 (
/.well-known/web-identity),可从configURL的 eTLD+1 处的/.well-known/web-identity获取。 - IdP 配置文件 (
/config.json),可从configURL获取。
这些都是
GET请求,不带 Cookie 且不遵循重定向。这有效地阻止了 IdP 了解是谁发出了请求以及哪个 RP 正在尝试连接。通过 FedCM 从浏览器发送的所有请求都包含一个
标头,以防止 CSRF 攻击。所有 IdP 端点都必须确认包含此标头。Sec-Fetch-Dest: webidentity - 众所周知的文件 (
-
IdP 响应请求的众所周知文件和
config.json文件。浏览器将get()请求中的配置文件 URL 与众所周知文件中有效配置文件 URL 列表进行验证。 -
如果浏览器将 IdP 的登录状态设置为
"logged-in",它将向 IdP 配置文件中的accounts_endpoint发出凭据请求(即,带有识别已登录用户的 Cookie)以获取用户账户详细信息。这是一个带 Cookie 但不带client_id参数或Origin标头的GET请求。这有效地阻止了 IdP 了解用户正在尝试登录哪个 RP。因此,返回的账户列表与 RP 无关。注意:如果所有 IdP 的登录状态都是
"logged-out",则get()调用将因NetworkErrorDOMException而拒绝,并且不会向任何 IdP 的accounts_endpoint发出请求。在这种情况下,由开发人员处理流程,例如提示用户去登录合适的 IdP。请注意,拒绝可能会有一些延迟,以避免将 IdP 登录状态泄露给 RP。 -
IdP 响应从其
accounts_endpoint请求的账户信息。这些是与用户 IdP Cookie 关联的所有账户的数组,适用于与 IdP 关联的任何 RP。 -
可选 如果包含在 IdP 配置文件中,浏览器将向
client_metadata_endpoint发出无凭据请求,以获取 RP 服务条款和隐私政策页面的位置。这是一个GET请求,将get()调用中传入的clientId作为参数发送,不带 Cookie。 -
可选 IdP 响应从
client_metadata_endpoint请求的 URL。 -
浏览器使用前两组请求获取的信息来创建 UI,要求用户选择一个 IdP(如果已登录多个)和一个账户来登录 RP。UI 还要求用户授予权限,允许使用他们选择的联合 IdP 账户登录 RP。
-
如果用户授予权限,浏览器将向
id_assertion_endpoint发出凭据请求,以从所选 IdP 请求所选账户的验证令牌。凭据以 HTTP
POST请求发送,带有 Cookie 和application/x-www-form-urlencoded的内容类型。如果调用失败,将返回一个错误负载,如ID 断言错误响应中所述,并且
get()返回的 Promise 将因错误而拒绝。 -
所选 IdP 会检查 RP 发送的账户 ID 是否与已登录账户的 ID 匹配,并且
Origin是否与 RP 的来源匹配,后者已提前在 IdP 中注册。如果一切正常,它将响应请求的验证令牌。注意:RP 的来源将在 RP 首次与 IdP 集成时通过一个完全独立的过程在 IdP 中注册。此过程将特定于每个 IdP。
-
当流程完成时,
get()Promise 将解析为IdentityCredential对象,该对象提供进一步的 RP 功能。最值得注意的是,此对象包含一个令牌,RP 可以验证该令牌来自 IdP(使用证书)并包含有关已登录用户的受信任信息。一旦 RP 验证了令牌,他们就可以使用其中包含的信息来登录用户并开始新会话,将他们注册到其服务,等等。令牌的格式和结构取决于 IdP,与 FedCM API 无关(RP 需要遵循 IdP 的说明)。
主动模式与被动模式
当 RP 用户通过 FedCM API 登录时,浏览器可以提供两种不同的 UI 模式:active 和 passive 模式。用于登录的模式由 identity 对象的 mode 选项控制
async function signIn() {
const identityCredential = await navigator.credentials.get({
identity: {
mode: active,
providers: [
{
configURL: "https://accounts.idp.example/config.json",
clientId: "********",
},
],
},
});
}
mode 的默认值为 passive。如果未设置 mode,或者明确设置为 passive,则浏览器可以通过 get() 调用启动登录流程,而无需直接用户交互。例如,您可能希望在用户导航到登录页面后立即启动登录流程,前提是他们有 IdP 账户可以登录。在此模式下,浏览器通常会向用户显示一个登录对话框,其中包含 providers 对象中指定的所有不同登录选项,用户可以选择最适合他们的选项,然后输入相应的凭据。
如果 mode 设置为 active,则浏览器要求通过用户操作(例如单击按钮,需要瞬态激活)启动登录流程,并且 providers 对象的长度只能为 1,否则 get() Promise 将被拒绝。此模式通常在 RP 希望为每个 IdP 选择提供单独的按钮时使用。当用户单击其中一个按钮时,会出现一个简化的对话框,只需他们输入该账户的凭据。
有关 Google Chrome 中如何呈现不同 UI 模式的示例,请参阅 privacysandbox.google.com 上的 FedCM UI 模式。
自动重新认证
FedCM 自动重新认证允许用户在首次使用 FedCM 认证后再次尝试登录 RP 时自动重新认证。"首次认证"是指用户在 RP 站点上的同一浏览器实例中,通过 FedCM 登录对话框首次创建账户或登录 RP 网站。
首次认证后,可以使用自动重新认证再次自动登录 RP 网站,而无需向用户显示“继续为…”确认提示。如果用户最近已授予权限以允许使用特定账户进行联合登录,则立即强制执行另一个明确的用户确认在隐私或安全方面没有任何好处。
自动重新认证行为由 get() 调用中的 mediation 选项控制
async function signIn() {
const identityCredential = await navigator.credentials.get({
identity: {
providers: [
{
configURL: "https://accounts.idp.example/config.json",
clientId: "********",
},
],
},
mediation: "optional", // this is the default
});
// isAutoSelected is true if auto-reauthentication occurred.
const isAutoSelected = identityCredential.isAutoSelected;
}
如果 mediation 设置为 optional 或 silent,则可以发生自动重新认证。
在以下条件下,将使用这些 mediation 选项进行自动重新认证:
- FedCM 可用。例如,用户未全局禁用 FedCM 或在 RP 设置中禁用 FedCM。
- 用户仅在此浏览器上通过 FedCM 使用一个账户登录到 RP 网站。如果存在多个 IdP 的账户,用户将不会自动重新认证。
- 用户已使用该账户登录到 IdP。
- 自动重新认证在过去 10 分钟内没有发生。此限制旨在阻止用户在注销后立即自动重新认证——这会造成非常令人困惑的用户体验。
- RP 在上次登录后没有调用
preventSilentAccess()。RP 可以使用此功能根据需要明确禁用自动重新认证。 - UI 模式为被动。
当满足这些条件时,一旦调用 get(),就会尝试自动重新认证用户。如果自动重新认证成功,用户将再次登录 RP 站点,而无需显示确认提示,并使用与之前相同的 IdP 账户和已验证的令牌。
如果自动重新认证失败,行为取决于所选的 mediation 值:
optional:用户将显示对话框并再次要求确认。因此,此选项通常适用于用户旅程未处于中途的页面,例如 RP 登录页面。silent:get()Promise 将被拒绝,开发人员需要处理引导用户返回登录页面以重新开始该过程。此选项适用于用户旅程正在进行中且您需要让他们保持登录直到完成的页面,例如电子商务网站结账流程的页面。
注意:IdentityCredential.isAutoSelected 属性指示联合登录是否使用自动重新认证进行。这有助于评估 API 性能并相应地改进用户体验。此外,当它不可用时,可能会提示用户通过显式用户中介(即 mediation: required 的 get() 调用)登录。
断开联合登录
RP 可以通过调用 IdentityCredential.disconnect() 将指定的联合登录账户从关联的 IdP 断开。此函数可以从顶级 RP 框架调用。
IdentityCredential.disconnect({
configURL: "https://idp.example.com/config.json",
clientId: "rp123",
accountHint: "account456",
});
为了使 disconnect() 调用正常工作,IdP 必须在其配置文件中包含一个 disconnect_endpoint。有关底层 HTTP 通信的更多详细信息,请参阅断开连接端点。
另见
- Federated Credential Management API on privacysandbox.google.com (2023)