此处介绍的部分更新在 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 进行了多项重要更改:
由于不再需要使用自定义
fetch()
函数提取密码,该函数很快就会被弃用。navigator.credentials.get()
现在接受枚举mediation
,而不是布尔标志unmediated
。新方法
navigator.credentials.create()
会异步创建凭据对象。
需要注意特征检测
如需了解用于访问基于密码的凭据和联合凭据的 Credential Management API 是否可用,请检查 window.PasswordCredential
或 window.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
。
navigator.credentials.get()
现在接受枚举中介
在 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?我们提供了迁移指南文档,您可以按照其中的说明升级到新版本。