为了提供复杂的用户体验,请务必帮助用户在您的网站上进行身份验证。经过身份验证的用户可以使用专用配置文件相互互动、在设备间同步数据,或在离线状态下处理数据;此列表还会不断增加。但对于最终用户来说,创建、记住和输入密码往往非常麻烦,特别是在移动设备的屏幕上,这会导致他们在不同网站上重复使用相同的密码。这当然会带来安全风险。
最新版本的 Chrome (51) 支持 Credential Management API。它是 W3C 的一项标准跟踪方案,可让开发者以编程方式访问浏览器的凭据管理器,并帮助用户更轻松地登录。
什么是 Credential Management API?
借助 Credential Management API,开发者能够存储和检索密码凭据及联合凭据,提供以下 3 项功能:
navigator.credentials.get()
navigator.credentials.store()
navigator.credentials.requireUserMediation()
利用这些简单的 API,开发者可以实现强大的功能,例如:
- 用户只需点按一下即可登录。
- 记住用户用于登录的联合账号。
- 会话过期后,让用户重新登录。
在 Chrome 的实现中,凭据将存储在 Chrome 的密码管理器中。如果用户登录了 Chrome,则可以在设备之间同步用户的密码。这些已同步的密码也可以分享给集成了 Android 版 Smart Lock for Passwords API 的 Android 应用,可提供顺畅的跨平台体验。
将 Credential Management API 与您的网站集成
在网站上使用 Credential Management API 的方式可能因其架构而异。是单页应用吗?是否为包含页面转换的旧版架构?登录表单是否仅位于页面顶部?登录按钮是否位于任何位置?用户是否可以在不登录的情况下浏览您的网站?联盟是否可在弹出式窗口中使用?还是需要跨多个网页进行互动?
几乎不可能涵盖所有这些情况,但我们来了解一个典型的单页应用。
- 最上面是注册表单。
- 用户点按“登录”按钮后,会转到登录表单。
- 注册表单和登录表单都具有 ID/密码凭据和联合身份验证(例如,使用 Google 登录和 Facebook 登录)的典型选项。
通过使用 Credential Management API,您可以向网站添加以下功能,例如:
- 登录时显示帐号选择器:当用户点按“登录”时,系统会显示原生帐号选择器界面。
- 存储凭据:在用户成功登录后,询问是否将凭据信息存储到浏览器的密码管理器中以供日后使用。
- 让用户自动重新登录:允许用户在会话过期后重新登录。
- 中介自动登录:在用户退出登录后,在用户下次访问时停用自动登录。
登录时显示账号选择器
在用户点按“登录”按钮与导航到登录表单之间,您可以使用 navigator.credentials.get() 来获取凭据信息。Chrome 会显示一个帐号选择器界面,用户可从界面中选择帐号。
获取密码凭据对象
如需将密码凭据显示为帐号选项,请使用 password: true
。
navigator.credentials.get({
password: true, // `true` to obtain password credentials
}).then(function(cred) {
// continuation
...
使用密码凭据登录
用户选择帐号后,解析函数将收到密码凭据。您可以使用 fetch()
将其发送到服务器:
// continued from previous example
}).then(function(cred) {
if (cred) {
if (cred.type == 'password') {
// Construct FormData object
var form = new FormData();
// Append CSRF Token
var csrf_token = document.querySelector('csrf_token').value;
form.append('csrf_token', csrf_token);
// You can append additional credential data to `.additionalData`
cred.additionalData = form;
// `POST` the credential object as `credentials`.
// id, password and the additional data will be encoded and
// sent to the url as the HTTP body.
fetch(url, { // Make sure the URL is HTTPS
method: 'POST', // Use POST
credentials: cred // Add the password credential object
}).then(function() {
// continuation
});
} else if (cred.type == 'federated') {
// continuation
使用联合凭据登录
如需向用户显示联合帐号,请将 federated
(它接受一组身份提供方)添加到 get()
选项。
navigator.credentials.get({
password: true, // `true` to obtain password credentials
federated: {
providers: [ // Specify an array of IdP strings
'https://accounts.google.com',
'https://www.facebook.com'
]
}
}).then(function(cred) {
// continuation
...
您可以检查凭据对象的 type
属性,以查看它是 PasswordCredential
(type == 'password'
) 还是 FederatedCredential
(type == 'federated'
)。如果凭据是 FederatedCredential
,您可以使用其包含的信息调用相应的 API。
});
} else if (cred.type == 'federated') {
// `provider` contains the identity provider string
switch (cred.provider) {
case 'https://accounts.google.com':
// Federated login using Google Sign-In
var auth2 = gapi.auth2.getAuthInstance();
// In Google Sign-In library, you can specify an account.
// Attempt to sign in with by using `login_hint`.
return auth2.signIn({
login_hint: cred.id || ''
}).then(function(profile) {
// continuation
});
break;
case 'https://www.facebook.com':
// Federated login using Facebook Login
// continuation
break;
default:
// show form
break;
}
}
// if the credential is `undefined`
} else {
// show form
存储凭据
当用户使用表单登录到您的网站时,您可以使用 navigator.credentials.store() 存储凭据。系统会提示用户是否存储该密钥。根据凭据类型,使用 new
PasswordCredential()
或 new
FederatedCredential()
创建要存储的凭据对象。
通过表单元素创建和存储密码凭据
以下代码使用 autocomplete
属性自动将表单的元素映射到 PasswordCredential 对象参数。
HTML
html
<form id="form" method="post">
<input type="text" name="id" autocomplete="username" />
<input type="password" name="password" autocomplete="current-password" />
<input type="hidden" name="csrf_token" value="******" />
</form>
JavaScript
var form = document.querySelector('\#form');
var cred = new PasswordCredential(form);
// Store it
navigator.credentials.store(cred)
.then(function() {
// continuation
});
创建和存储联合凭据
// After a federation, create a FederatedCredential object using
// information you have obtained
var cred = new FederatedCredential({
id: id, // The id for the user
name: name, // Optional user name
provider: 'https://accounts.google.com', // A string that represents the identity provider
iconURL: iconUrl // Optional user avatar image url
});
// Store it
navigator.credentials.store(cred)
.then(function() {
// continuation
});
让用户自动重新登录
如果用户离开您的网站,稍后又返回,会话可能已过期。请不要在每次返回时都要要求用户输入密码。让用户自动重新登录。
获取凭据对象
navigator.credentials.get({
password: true, // Obtain password credentials or not
federated: { // Obtain federation credentials or not
providers: [ // Specify an array of IdP strings
'https://accounts.google.com',
'https://www.facebook.com'
]
},
unmediated: true // `unmediated: true` lets the user automatically sign in
}).then(function(cred) {
if (cred) {
// auto sign-in possible
...
} else {
// auto sign-in not possible
...
}
});
该代码应类似于您在“登录时显示帐号选择器”部分中看到的代码。唯一的区别在于您需要设置 unmediated: true
。
这样会立即解析该函数,并为您提供相应凭据,以便用户自动登录。需要满足以下条件:
- 用户在诚挚的欢迎消息中感谢了自动登录功能。
- 用户之前使用 Credential Management API 登录了网站。
- 用户只为您的源存储了一个凭据。
- 用户在上一次会话中没有明确退出。
如果不满足其中任何一个条件,函数都将被拒绝。
通过中介功能自动登录
当用户从您的网站退出帐号时,您有责任确保用户不会自动重新登录。为确保这一点,Credential Management API 提供了一种称为“中介”的机制。您可以通过调用 navigator.credentials.requireUserMediation()
启用中介模式。只要启用了用户针对源站的中介状态(同时使用 unmediated: true
和 navigator.credentials.get()
),该函数便会通过 undefined
进行解析。
通过中介功能自动登录
navigator.credentials.requireUserMediation();
常见问题解答
网站上的 JavaScript 能否检索原始密码?
不可以。您只能通过 PasswordCredential
获取密码,并且不会以任何方式公开。
可以使用 Credential Management API 存储一个 ID 的 3 位数吗? 目前不是。期待您就该规范提供反馈意见。
我可以在 iframe 中使用 Credential Management API 吗?
此 API 仅限于顶级上下文。在 iframe 中对 .get()
或 .store()
的调用会立即解析,而不会产生任何效力。
我可以将我的密码管理 Chrome 扩展程序与 Credential Management API 集成吗?
您可以替换 navigator.credentials
并将其挂接到 Chrome 扩展程序,以连接到 get()
或 store()
凭据。
资源
如需详细了解 Credential Management API,请参阅集成指南。