如要提供複雜的使用者體驗,請務必協助使用者驗證您的網站。已驗證的使用者可以透過專屬設定檔與彼此互動、跨裝置同步處理資料,或在離線狀態下處理資料,這份清單則繼續啟用。但是建立、記住及輸入密碼對使用者而言往往相當麻煩,特別是在行動裝置畫面上,導致使用者在不同網站上重複使用相同密碼。這當然是安全性風險
最新版本的 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,就能在所有裝置上同步處理使用者的密碼。這些同步的密碼也可以和已整合 密碼專用 Smart Lock for Android 的 Android 應用程式分享,提供順暢的跨平台體驗。
將 Credential Management API 與您的網站整合
搭配網站使用 Credential Management API 的方式,可能會因架構而異。是否為單一頁面應用程式?這是採用頁面轉換的舊版架構嗎?登入表單是否只位於頁面頂端?任何位置都有登入按鈕嗎?使用者在不登入的情況下 是否能夠充分瀏覽網站?聯盟功能是否可在彈出式視窗內運作?還是需要跨多個網頁互動?
雖然幾乎不可能涵蓋上述所有情況,但我們來看看典型的單頁應用程式。
- 網頁頂端會顯示註冊表單。
- 使用者只要輕觸「登入」按鈕,即可前往登入表單。
- 註冊和登入表單都有 ID/密碼憑證和聯盟的常見選項,例如 Google 登入和 Facebook 登入。
使用 Credential Management API 即可將下列功能新增至網站,例如:
- 在登入時顯示帳戶選擇工具:在使用者輕觸「登入」時顯示原生帳戶選擇工具 UI。
- 儲存憑證:登入「成功」後,請詢問是否要將憑證資訊儲存在瀏覽器的密碼管理工具供日後使用。
- 讓使用者自動重新登入:在工作階段過期時,讓使用者重新登入。
- 中介自動登入:使用者登出後,請在下次使用者造訪時停用自動登入功能,
登入時顯示帳戶選擇工具
使用者輕觸「登入」按鈕並前往登入表單時,您可以使用 navigator.credentials.get() 取得憑證資訊。Chrome 會顯示帳戶選擇工具 UI,讓使用者選擇帳戶。
取得密碼憑證物件
如要顯示密碼憑證做為帳戶選項,請使用 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 儲存 3 組 ID 嗎?目前還不是。非常感謝您對規格提出意見。
我可以在 iframe 中使用 Credential Management API 嗎?
API 僅適用於頂層內容。在 iframe 中對 .get()
或 .store()
的呼叫會立即解析,不會產生任何作用。
可以將密碼管理 Chrome 擴充功能與 Credential Management API 整合嗎?
您可以覆寫 navigator.credentials
,並將其掛接到您的 Chrome 擴充功能,設為 get()
或 store()
憑證。
資源
如要進一步瞭解 Credential Management API,請參閱整合指南。