Credential Management API 的最新动态

此处介绍的部分更新在 Google I/O 大会的 Secure and Seamless Sign-In: Keeping Users Engaged 会话中有所介绍:

Chrome 57

Chrome 57 对 Credential Management API 做出了这一重大更改。

可以使用其他子网域中的凭据

Chrome 现在可以使用 Credential Management API 检索存储在其他子网域中的凭据。例如,如果密码存储在 login.example.com 中,www.example.com 上的脚本可以将其显示为账号选择器对话框中的账号项之一。

您必须使用 navigator.credentials.store() 明确存储密码,以便当用户通过点按对话框选择凭据时,密码会被传递并复制到当前来源。

存储后,该密码便可在完全相同的来源 www.example.com 中作为凭据使用。

在以下屏幕截图中,存储在 login.aliexpress.com 下的凭据信息对 m.aliexpress.com 可见,供用户选择:

显示所选子网域登录详细信息的账号选择器

Chrome 60

Chrome 60 对 Credential Management API 进行了多项重要更改:

需要注意特征检测

如需了解用于访问基于密码的凭据和联合凭据的 Credential Management API 是否可用,请检查 window.PasswordCredentialwindow.FederatedCredential 是否可用。

if (window.PasswordCredential || window.FederatedCredential) {
  // The Credential Management API is available
}

PasswordCredential 对象现在包含密码

Credential Management API 在处理密码时采用了保守的方法。它会将密码隐藏起来,不让 JavaScript 看到,因此开发者需要通过 fetch() API 的扩展程序将 PasswordCredential 对象直接发送到其服务器进行验证。

但这种方法会带来一些限制。我们收到了开发者反馈,称他们无法使用该 API,原因如下:

  • 他们必须将密码作为 JSON 对象的一部分发送。

  • 他们必须将密码的哈希值发送到其服务器。

在执行安全分析后,我们发现将密码隐藏起来并不能像我们预期的那样有效地防范所有攻击途径,因此决定做出更改。

Credential Management API 现在会在返回的凭据对象中包含原始密码,以便您以纯文本形式访问该密码。您可以使用现有方法将凭据信息传送到服务器:

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    mediation: 'silent'
}).then(passwordCred => {
    if (passwordCred) {
    let form = new FormData();
    form.append('email', passwordCred.id);
    form.append('password', passwordCred.password);
    form.append('csrf_token', csrf_token);
    return fetch('/signin', {
        method: 'POST',
        credentials: 'include',
        body: form
    });
    } else {

    // Fallback to sign-in form
    }
}).then(res => {
    if (res.status === 200) {
    return res.json();
    } else {
    throw 'Auth failed';
    }
}).then(profile => {
    console.log('Auth succeeded', profile);
});

自定义提取功能即将弃用

如需确定您是否使用自定义 fetch() 函数,请检查它是否使用 PasswordCredential 对象或 FederatedCredential 对象作为 credentials 属性的值,例如:

fetch('/signin', {
    method: 'POST',
    credentials: c
})

建议使用常规的 fetch() 函数(如前面的代码示例所示),或使用 XMLHttpRequest

在 Chrome 60 之前,navigator.credentials.get() 接受带有布尔标志的可选 unmediated 属性。例如:

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    unmediated: true
}).then(c => {

    // Sign-in
});

设置 unmediated: true 可阻止浏览器在传递凭据时显示账号选择器。

该标志现已扩展为中介。 在以下情况下,可能会发生用户中介:

  • 用户需要选择一个账号进行登录。

  • 用户希望在 navigator.credentials.requireUseMediation() 调用后明确登录。

mediation 值选择以下选项之一:

mediation 与布尔值标志相比 行为
silent 等于 unmediated: true 传递凭据,但未显示账号选择器。
optional 等于 unmediated: false 如果之前调用了 preventSilentAccess(),则会显示账号选择器。
required 新选项 始终显示账号选择器。 如果您想让用户使用原生账号选择器对话框切换账号,此属性非常有用。

在此示例中,系统会在不显示账号选择器的情况下传递凭据,这相当于之前的标志 unmediated: true

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    mediation: 'silent'
}).then(c => {

    // Sign-in
});

requireUserMediation() 已重命名为 preventSilentAccess()

为了与 get() 调用中提供的新 mediation 属性保持一致,navigator.credentials.requireUserMediation() 方法已重命名为 navigator.credentials.preventSilentAccess()

重命名的方法可防止在未显示账号选择器的情况下传递凭据(有时称为“无需用户中介”)。如果用户退出某个网站或取消注册某个网站,并且不希望在下次访问时自动登录,此属性非常有用。

signoutUser();
if (navigator.credentials) {
    navigator.credentials.preventSilentAccess();
}

使用新方法 navigator.credentials.create() 异步创建凭据对象

现在,您可以选择使用新方法 navigator.credentials.create() 异步创建凭据对象。请继续阅读,了解同步和异步方法之间的比较。

创建 PasswordCredential 对象

同步方法
let c = new PasswordCredential(form);
异步方法(新)
let c = await navigator.credentials.create({
    password: form
});

或者:

let c = await navigator.credentials.create({
    password: {
    id: id,
    password: password
    }
});

创建 FederatedCredential 对象

同步方法
let c = new FederatedCredential({
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
});
异步方法(新)
let c = await navigator.credentials.create({
    federated: {
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
    }
});

迁移指南

是否已实现 Credential Management API?我们提供了迁移指南文档,您可以按照其中的说明升级到新版本。