为了提供完善的用户体验,请务必帮助用户对您的网站进行身份验证。经过身份验证的用户可以使用专用个人资料相互互动、跨设备同步数据,或在离线状态下处理数据;诸如此类的用例不胜枚举。但是,对于最终用户来说,创建、记住和输入密码通常很麻烦,尤其是在移动屏幕上,这会导致他们在不同的网站上重复使用相同的密码。这当然会带来安全风险。
最新版本的 Chrome(51)支持 Credential Management API。这是 W3C 的标准轨道提案,可让开发者以编程方式访问浏览器的凭据管理器,并帮助用户更轻松地登录。
什么是 Credential Management API?
借助 Credential Management API,开发者可以存储和检索密码凭据和联合凭据,该 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,请参阅集成指南。