原文鏈接: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()
認證對象。