category
本文描述了依赖方(RP)可以使用联合凭据管理(FedCM)API通过身份提供程序(IdP)执行联合登录的过程。
调用get()方法
RP可以使用标识选项调用navigator.credential.get(),以请求用户使用他们已经在浏览器上登录的现有IdP帐户登录RP。IdP通过其客户端ID来识别RP,该客户端ID是由IdP在特定于IdP的单独进程中发布给RP的。IdP使用登录时提供给浏览器的凭据(cookie)来识别特定用户。
如果IdP成功验证了用户身份,该方法将返回一个承诺,该承诺将通过IdentityCredential对象实现。此对象包含一个令牌,该令牌包含已使用IdP的数字证书签名的用户身份信息。
RP将令牌发送到其服务器以验证证书,一旦成功,就可以使用令牌中的(现在受信任的)身份信息将他们登录到其服务(启动新会话),如果他们是新用户,则可以将他们注册到其服务,等等。
如果用户从未登录过IdP或已注销,则get()方法会拒绝并返回错误,RP可以将用户引导到IdP登录页面以登录或创建帐户。
注意:验证令牌令牌的确切结构和内容对FedCM API和浏览器是不透明的。IdP决定它的语法和用法,RP需要遵循IdP提供的说明(例如,请参阅验证服务器端的Google ID令牌),以确保他们正确使用它。
典型的请求可能如下所示:
JS
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)。
注意:目前FedCM只允许使用单个IdP调用API,即identity.providers数组的长度必须为1。为了给用户提供身份提供者的选择,RP需要分别为每个提供者调用get()。这种情况将来可能会改变。
上面的示例还包括几个可选功能:
- identity.context指定用户使用FedCM进行身份验证的上下文。例如,是首次注册此帐户,还是使用现有帐户登录?浏览器使用这些信息来改变其FedCM UI中的文本,以更好地适应上下文。
- nonce属性提供一个随机的nonce值,以确保对此特定请求发出响应,从而防止重放攻击。
loginHint
属性提供有关浏览器应为用户登录提供的帐户选项的提示。此提示与IdP从帐户列表终结点提供的login_in提示值相匹配。
浏览器请求IdP配置文件,并执行下面详细介绍的登录流程。有关用户可能期望从浏览器提供的UI进行何种交互的更多信息,请参阅使用身份提供程序登录到依赖方。
FedCM登录流程
登录流程涉及三方——RP应用程序、浏览器本身和IdP。下图直观地总结了正在发生的情况。
下面详细描述的流程的可视化表示
流程如下:
- RP调用navigator.credentials.get()来启动登录流。
- 浏览器从get()调用中提供的configURL请求两个文件:
- 众所周知的文件(/.aknowledge/web identity),可从configURL的eTLD+1上的/.aknowredge/web dentity获得。
- IdP配置文件(/config.json),可在configURL中获得。
- 这两个都是GET请求,它们没有cookie,也不遵循重定向。这有效地防止了IdP了解是谁提出了请求以及哪个RP试图连接。所有通过FedCM从浏览器发送的请求都包括一个Sec-Fetch-Dest:webidentity头,以防止CSRF攻击。所有IdP终结点都必须确认包含此标头。
- IdP使用请求的已知文件和config.json文件进行响应。浏览器根据已知文件中的有效配置URL列表验证get()请求中的配置文件URL。
- 如果浏览器将IdP的登录状态设置为“已登录”,则会向IdP配置文件内的accounts_endpoint发出认证请求(即使用标识登录用户的cookie),以获取用户的帐户详细信息。这是一个带有cookie的GET请求,但没有client_id参数或Origin标头。这有效地阻止了IdP了解用户试图登录的RP。因此,返回的帐户列表与RP无关。
- 注意:如果IdP登录状态为“logge-out”,则get()调用会拒绝NetworkError DOMException,并且不会向IdP的accounts_endpoint发出请求。在这种情况下,由开发人员来处理流,例如,通过提示用户转到并登录到合适的IdP。请注意,拒绝可能会有一些延迟,以避免将IdP登录状态泄露给RP。
- IdP使用从accounts_endpoint请求的帐户信息进行响应。这是与IdP相关联的任何RP的用户IdP cookie相关联的所有帐户的数组。
- 可选如果包含在IdP配置文件中,则浏览器会向client_metadata_endpoint发出一个无条件请求,以获取IdP服务条款和隐私策略页面的位置。这是一个发送的GET请求,其中clientId作为参数传递到GET()调用中,不包含cookie。
- 可选IdP使用从client_metadata_endpoint请求的URL进行响应。
- 浏览器使用前两个请求获得的信息来创建UI,要求用户选择登录RP的帐户(在有多个可用帐户的情况下)。UI还要求用户允许使用他们选择的联合IdP帐户登录RP。
- 注意:在这个阶段,如果用户以前在当前浏览器实例中使用联合RP帐户进行过身份验证(即使用RP创建了一个新帐户或使用现有帐户登录到RP的网站),则他们可能能够自动重新进行身份验证,这取决于在get()调用中中介选项的设置。如果是这样,一旦调用了get(),用户将自动登录,而无需输入凭据。有关更多详细信息,请参阅“自动重新身份验证”部分。
- 如果用户授予这样做的权限,浏览器会向id_assertion_endpoint发出一个有证书的请求,以从所选帐户的IdP请求验证令牌。凭据在HTTP POST请求中发送,其中包含cookie和内容类型为application/x-www-form-urlencoded。如果调用失败,将返回一个错误负载,如ID断言错误响应中所述,并且get()返回的promise将与错误一起被拒绝。
- IdP检查RP发送的帐户ID是否与已经登录的帐户的ID匹配,以及Origin是否与RP的Origin匹配,RP的Original将预先在IdP中注册。如果一切看起来都很好,它将使用请求的验证令牌进行响应。
- 注:当RP首次与IdP集成时,RP的起源将在一个完全独立的过程中与IdP注册。此过程将针对每个IdP。
- 流完成后,get()promise将使用IdentityCredential对象进行解析,该对象提供了进一步的RP功能。最值得注意的是,该对象包含一个令牌,RP可以验证该令牌来自IdP(使用证书),并且包含有关已登录用户的可信信息。一旦RP验证了令牌,他们就可以使用包含的信息让用户登录并启动新会话,为他们的服务注册等。令牌的格式和结构取决于IdP,与FedCM API无关(RP需要遵循IdP的指示)。
自动重新身份验证
FedCM自动重新身份验证允许用户在使用FedCM进行初始身份验证后尝试再次登录到RP时自动重新进行身份验证。“初始身份验证”是指用户在RP网站上的同一浏览器实例上首次通过FedCM登录对话框创建帐户或登录RP网站。
初始身份验证后,可以使用自动重新身份验证再次自动登录RP网站,而无需向用户显示“继续作为…”确认提示。如果用户最近授予了允许对特定帐户进行联合登录的权限,则立即强制执行另一个明确的用户确认没有隐私或安全方面的好处。
自动重新身份验证行为由get()调用中的中介选项控制:
JS
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
设置为可选或静默,则可以进行自动重新身份验证。
使用这些中介选项,自动重新身份验证将在以下条件下发生:
- FedCM可供使用。例如,用户没有在全局或RP的设置中禁用FedCM。
- 用户仅使用一个帐户通过FedCM在此浏览器上登录RP网站。
- 用户已使用该帐户登录到IdP。
- 在过去10分钟内没有进行自动重新身份验证。实施这一限制是为了阻止用户在注销后立即进行自动重新身份验证,这将导致用户体验非常混乱。
- RP在上一次登录后没有调用preventSilentAccess()。如果需要,RP可以使用它显式禁用自动重新身份验证。
当满足这些条件时,一旦调用get(),就会尝试自动重新验证用户。如果自动重新身份验证成功,用户将使用与以前相同的IdP帐户和验证令牌再次登录RP站点,而不会显示确认提示。
如果自动重新身份验证失败,则行为取决于所选的中介值:
- 可选:用户将看到对话框,并要求再次确认。因此,在用户旅程不在中间的页面(如RP登录页面)上使用此选项往往是有意义的。
- silent:get()promise将被拒绝,开发人员将需要处理引导用户返回登录页面以重新启动流程的问题。这个选项在用户旅程正在进行的页面上是有意义的,您需要让他们一直登录到完成,例如电子商务网站上的结账流程页面。
注意:IdentityCredential.isAutoSelected属性提供了是否使用自动重新身份验证执行联合登录的指示。这有助于评估API的性能,并相应地提高用户体验。此外,当它不可用时,可能会提示用户使用显式用户中介登录,这是一个带有中介的get()调用:必需。
另请参阅
- Federated Credential Management API on developer.chrome.com (2023)
- 登录 发表评论