如要提供精緻的使用者體驗,請務必協助使用者驗證網站。已驗證的使用者可以使用專屬設定檔彼此互動、在不同裝置間同步處理資料,或在離線時處理資料,這類情況不勝枚舉。不過,對於使用者來說,建立、記住和輸入密碼往往相當麻煩,尤其是在行動裝置螢幕上,因此使用者會在不同網站重複使用相同的密碼。這當然會帶來安全風險。
最新版的 Chrome (51) 支援 Credential Management API。這是 W3C 的標準追蹤提案,可讓開發人員以程式輔助方式存取瀏覽器的憑證管理工具,並協助使用者更輕鬆地登入。
什麼是憑證管理 API?
憑證管理 API 可讓開發人員儲存及擷取密碼憑證和聯合憑證,並提供 3 項功能:
navigator.credentials.get()
navigator.credentials.store()
navigator.credentials.requireUserMediation()
開發人員可以透過這些簡單的 API 執行強大的功能,例如:
- 讓使用者只要輕觸一下就能登入。
- 記住使用者用來登入的聯合帳戶。
- 在工作階段到期時,讓使用者重新登入。
在 Chrome 的實作中,憑證會儲存在 Chrome 的密碼管理工具中。如果使用者已登入 Chrome,就能在各裝置間同步處理使用者的密碼。這些已同步的密碼也可以與已整合 Android 版 Smart Lock for Passwords API 的 Android 應用程式共用,以提供順暢的跨平台體驗。
將憑證管理 API 整合至網站
您在網站上使用憑證管理 API 的方式,可能會因架構而異。這是單頁應用程式嗎?是否為具有頁面轉場的舊版架構?登入表單是否只位於頂端頁面?是否在各處顯示登入按鈕?使用者可以在不登入的情況下,瀏覽您的網站嗎?聯盟是否可在彈出式視窗中運作?還是需要跨多個網頁進行互動?
我們幾乎無法涵蓋所有情況,但讓我們來看看典型的單頁應用程式。
- 頂端頁面是註冊表單。
- 輕觸「登入」按鈕後,使用者會前往登入表單。
- 註冊和登入表單都提供 ID/密碼憑證和聯合登入的常見選項,例如 Google 登入和 Facebook 登入。
使用憑證管理 API 後,您就能在網站上新增下列功能,例如:
- 登入時顯示帳戶選擇器:在使用者輕觸「登入」時顯示原生帳戶選擇器 UI。
- 儲存憑證:在登入成功後,提供將憑證資訊儲存至瀏覽器密碼管理工具的選項,以供日後使用。
- 讓使用者自動重新登入:如果工作階段已過期,請讓使用者重新登入。
- 中介自動登入:使用者登出後,系統會在使用者下次造訪時停用自動登入功能。
在登入時顯示帳戶選擇器
在使用者輕觸「Sign In」按鈕和前往登入表單之間,您可以使用 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()
選項,這會採用一系列的 ID 供應器。
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
。
這會立即解析函式,並提供憑證,讓您自動登入使用者。但有幾個條件:
- 使用者在歡迎畫面中確認自動登入功能。
- 使用者先前曾使用憑證管理 API 登入網站。
- 使用者只儲存一個來源憑證。
- 使用者未在先前的工作階段中明確登出。
如果不符合上述任一條件,系統就會拒絕該函式。
自動登入中介服務
當使用者從您的網站登出時,您有責任確保使用者不會自動重新登入。為確保這項功能,憑證管理 API 提供稱為「中介」的機制。您可以呼叫 navigator.credentials.requireUserMediation()
來啟用中介模式。只要使用者針對來源啟用中介服務狀態,使用 unmediated: true
搭配 navigator.credentials.get()
,該函式就會透過 undefined
解析。
自動登入仲介
navigator.credentials.requireUserMediation();
常見問題
網站上的 JavaScript 是否可以擷取原始密碼?否。您只能透過 PasswordCredential
取得密碼,而且密碼無法透過任何方式揭露。
是否可以使用憑證管理 API 為 ID 儲存 3 組數字?目前不行。我們非常感謝您提供規格相關意見回饋。
我可以在 iframe 中使用憑證管理 API 嗎?這個 API 僅限於頂層情境。在 iframe 中對 .get()
或 .store()
的呼叫會立即解析,但不會產生效果。
可以將密碼管理 Chrome 擴充功能與 Credential Management API 整合嗎?您可以覆寫 navigator.credentials
,並將其鉤掛至 Chrome 擴充功能,以便使用 get()
或 store()
憑證。
資源
如要進一步瞭解 Credential Management API,請參閱整合指南。