Credential Management API 的最新动态

Google I/O 大会专题演讲安全、无缝登录:持续吸引用户中介绍了一些相关更新:

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 对象的一部分发送。

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

在进行了安全分析并确定在 JavaScript 中隐藏密码并不会像我们希望的那样有效地阻止所有攻击途径,我们决定做出一项改变。

现在,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 实现?您可以参照我们的迁移指南文档升级到新版本。