使用憑證管理 API 簡化登入流程

如要提供複雜的使用者體驗,請務必協助使用者驗證您的網站。已驗證的使用者可以透過專屬設定檔與彼此互動、跨裝置同步處理資料,或在離線狀態下處理資料,這份清單則繼續啟用。但是建立、記住及輸入密碼對使用者而言往往相當麻煩,特別是在行動裝置畫面上,導致使用者在不同網站上重複使用相同密碼。這當然是安全性風險

最新版本的 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,讓使用者選擇帳戶。

系統會彈出帳戶選擇工具 UI,讓使用者選擇要登入的帳戶。
系統會彈出帳戶選擇工具 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() 建立要儲存的憑證物件。

Chrome 會詢問使用者是否要儲存憑證 (或聯盟提供者),
Chrome 會詢問使用者是否要儲存憑證 (或聯盟提供者)

建立及儲存表單元素的密碼憑證

以下程式碼使用 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: truenavigator.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,請參閱整合指南