原文链接:http://lea.verou.me/2015/12/my-positive-experience-as-a-woman-in-tech/javascript
为了提供优质的用户体验,咱们应该帮助用户在不一样网页进行身份认证。完成认证的用户能够在不一样网页拥有不一样的资料,在多设备之间同步数据,或是在离线状况下处理数据;能够扩展的功能数之不尽。可是建立帐号、记住和输入密码对用户来讲很是麻烦,尤为是在手机端,这一般致使用户在不一样网站使用同一份密码。这在安全性上有很大的风险。html
Chrome 51(最新版本)支持了Credential Management API(证书管理API)。它遵循了W3C提议的标准,为开发者提供了管理浏览器认证的入口,以帮助用户以更简单的方式登陆。java
经过认证管理API, 开发者能够保存和获取密码认证信息和联合认证信息。它提供了一下3个方法:android
navigator.credentials.get()
git
navigator.credentials.store()
github
navigator.credentials.requireUserMediation()
web
经过使用这些API,开发者能够完成如下强大的功能:api
让用户能够经过一次点击完成登陆数组
记录用户登陆时使用的联合认证帐号浏览器
当session过时时,帮助用户从新登陆
在Chrome的实现中,认证信息会被保存在Chrome的密码管理器中。用户登录后,能够在多设备之间同步密码。同步的密码也能够被分享给Android应用,只要这些应用集成了Smart Lock for Passwords for Android,以提供无缝的跨平台体验.
如何使用认证管理API,取决于你的网站架构是如何设计的。你的网站是一个单页应用?是一个涉及页面切换的传统架构?只能在首页登陆?仍是处处都能登陆?用户能否在不登陆的状况下浏览网页?登陆操做是否在弹出的窗口中进行?仍是说须要操做不一样的页面才能登陆。
咱们不可能覆盖全部的场景,但让咱们先经过一个典型的单页应用了解一下:
首页是一个登陆表单。
点击“登陆”按钮时,用户会被导向一个登陆表单。
注册和登陆表单都提供了id/password认证与联合认证登陆的选项,例如:经过Google登陆,或经过Facebook登陆。
使用认证管理API,咱们能够为网站添加如下功能,例如:
在用户登陆时,显示帐号选择框: 当用户点击“登陆”时,弹出原生帐号选择框。
保存认证信息: 在用户成功登陆后,使用浏览器的密码管理器保存认证信息,以便往后使用。
调解自动登陆: 一旦用户退出登陆,在用户下一次访问时,中止自动登陆。
注意:这些API只能在安全网站中使用,例如HTTPS网站、locolhost
在用户点击了“登陆”按钮,并跳到登陆表单以前,你能够经过navigator.credentials.get()方法得到认证信息。Chrome会弹出一个帐号选择框,供用户选择。
弹出了一个帐号选择框,用户可选择一个帐号进行登陆。
若是想支持经过密码认证登陆,请使用password: true
navigator.credentials.get({ password: true, // 设置为true,以获取密码认证对象 }).then(function(cred) { // 继续 ...
当用户选择了一个帐号时,resolve函数会收到一个密码认证对象,你能够经过fetch()
方法将信息发送到服务器。
// 延续上一个例子 }).then(function(cred) { if (cred) { if (cred.type == 'password') { // 构建FormData对象 var form = new FormData(); // 添加CSRF令牌 var csrf_token = document.querySelector('csrf_token').value; form.append('csrf_token', csrf_token); // 你能够将额外信息添加到`.additionalData` cred.additionalData = form; // 将认证对象做为`credentials`经过`POST`请求发送 // id, 密码和额外信息会被加密,并做为HTTP主体被发送给接口 fetch(url, { // 请保证url是HTTPS连接 method: 'POST', // 使用POST方法 credentials: cred // 添加密码认证对象 }).then(function() { // 继续 }); } else if (cred.type == 'federated') { // 继续
若是想为用户展现联合登陆帐号,请在调用get()
方法时,经过federated
选项定义一个包含帐号提供者id的数组。
密码管理器保存了多个帐号
navigator.credentials.get({ password: true, // 设置为true,以得到密码认证对象 federated: { providers: [ // 定义一个由联合帐号供应者id组成的数组 '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`属性包含了联合帐号供应者的id switch (cred.provider) { case 'https://accounts.google.com': // 使用Google Sign-In进行联合登陆 var auth2 = gapi.auth2.getAuthInstance(); // 使用Google Sign-In库时,能够经过login_hint指定一个帐号 return auth2.signIn({ login_hint: cred.id || '' }).then(function(profile) { // 继续 }); break; case 'https://www.facebook.com': // 使用Facebook Login进行联合登陆 // 继续 break; default: // 显示表单 break; } } // 若是cred是undefined } else { // 显示表单
当用户经过表单登陆你的网站时,你可使用navigator.credentials.store()来保存认证信息。浏览器会询问用户是否但愿保存。你能够根据认证的类型,决定使用new PasswordCredential()
仍是new FederatedCredential()
来建立认证对象并保存。
Chrome询问用户是否但愿保存认证信息(或是做为联合帐号)
如下代码经过属性autocomplete
,自动将表单元素 映射为PasswordCredential对象的参数。
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); // 保存认证对象 navigator.credentials.store(cred) .then(function() { // 继续 });
// 在联合认证后,经过你得到的信息建立一个FederatedCredential对象 var cred = new FederatedCredential({ id: id, // 用户id name: name, // 可选的用户名 provider: 'https://accounts.google.com', // 联合帐号提供者的id iconURL: iconUrl // 可选的用户头像地址 }); // 保存认证对象 navigator.credentials.store(cred) .then(function() { // 继续 });
当用户再次访问网站时,session有可能已经失效了。咱们没必要麻烦用户每次回访的时候从新输入密码。能够帮助他们自动从新登陆。
当用户自动登陆时,会弹出一个通知
navigator.credentials.get({ password: true, federated: { providers: [ 'https://accounts.google.com', 'https://www.facebook.com' ] }, unmediated: true // 设置为true,以支持用户自动登陆 }).then(function(cred) { if (cred) { // 能够自动登陆 ... } else { // 不能够自动登陆 ... } });
这段代码与你在前面的“显示帐号选择框”部分的代码类似。惟一的区别是这儿设置了unmediated: true
。
这会使函数立刻resolve
,并返回一个认证对象,帮助用户自动登陆。自动登陆有如下条件:
浏览器已显式地告知用户正在进行自动登陆
用户曾经经过认证管理API登录了网站
用户在浏览你的网站时只保存了一个认证对象
用户在上一次访问时没有主动退出登陆
若是任意条件不符合,这个函数便会被reject
当用户退出登陆时,应该由你来确保用户下次回访时不会自动登陆 。认证管理API提供了一种叫做mediation(调解)的机制来确保这一点。你能够经过调用navigator.credentials.requireUserMediation()
来开启调解模式。只要用户在这个网站中的调解状态为开启,那么若是你在navigator.credentials.get()
方法中选择了unmediate:true
,这个函数会在resolve
时,传入undefined
。
navigator.credentials.requireUserMediation();
在网页中,Javascript是否有可能得到原始密码?
不能。密码只能做为PasswordCredential
对象中的一部分,对外是不可访问的。
No. You can only obtain passwords as a part of PasswordCredential
and it’s not exposable by any means.
Is it possible to store 3 set of digits for an id using Credential Management API?
咱们能够经过认证管理API为一个id保存三组数字吗?
目前还不行。咱们很是感谢你对标准的反馈
我能够在iframe中使用认证管理API吗?
这个API只能在最高级的上下文中使用。若是在iframe中调用.get()
或.store()
方法,这些方法会立刻resolve
,而且不会产生任何效果。
我能够在个人密码管理Chrome扩展中集成认证管理API吗?
你能够重写navigator.credentials
,并将它指向你的Chrome扩展,由扩展来get()
或store()
认证对象。