Uproszczenie procesu logowania za pomocą interfejsu API do zarządzania danymi logowania

Aby zapewnić użytkownikom wygodę korzystania z witryny, warto pomóc im w uwierzytelnieniu się. Użytkownicy uwierzytelnieni mogą wchodzić w interakcje z innymi użytkownikami za pomocą dedykowanego profilu, synchronizować dane na różnych urządzeniach lub przetwarzać dane w trybie offline. A to tylko niektóre z możliwości. Tworzenie, zapamiętywanie i wpisywanie haseł bywa jednak uciążliwe dla użytkowników, zwłaszcza na ekranach urządzeń mobilnych, co prowadzi do używania tych samych haseł na różnych stronach. Jest to oczywiście ryzyko dla bezpieczeństwa.

Najnowsza wersja Chrome (51) obsługuje interfejs Credential Management API. Jest to propozycja standardów W3C, która daje deweloperom dostęp programowy do menedżera danych logowania w przeglądarce i ułatwia użytkownikom logowanie.

Czym jest interfejs Credential Management API?

Interfejs Credential Management API umożliwia programistom przechowywanie i pobieranie danych logowania z hasłem oraz danych logowania federacyjnych. Zawiera 3 funkcje:

  • navigator.credentials.get()
  • navigator.credentials.store()
  • navigator.credentials.requireUserMediation()

Te proste interfejsy API pozwalają programistom na:

  • Umożliw użytkownikom logowanie się jednym kliknięciem.
  • Zapamiętaj konto federacyjne, którego użył użytkownik do zalogowania się.
  • Po upływie sesji zaloguj użytkowników ponownie.

W przypadku implementacji w Chrome dane uwierzytelniające będą przechowywane w menedżerze haseł Chrome. Jeśli użytkownicy są zalogowani w Chrome, mogą synchronizować hasła na różnych urządzeniach. Takie zsynchronizowane hasła można też udostępniać aplikacjom na Androida zintegrowanym z interfejsem API Smart Lock na hasła na Androida dla wygody użytkowników na wielu platformach.

Integracja interfejsu Credential Management API z witryną

Sposób korzystania z interfejsu Credential Management API w przypadku witryny może się różnić w zależności od jej architektury. Czy to aplikacja jednostronicowa? Czy jest to starsza architektura z przejściami między stronami? Czy formularz logowania znajduje się tylko na stronie głównej? Czy przyciski logowania są dostępne wszędzie? Czy użytkownicy mogą przeglądać Twoją witrynę bez logowania się? Czy federacja działa w oknach wyskakujących? Czy wymaga interakcji na wielu stronach?

Uwzględnienie wszystkich tych przypadków jest praktycznie niemożliwe, ale przyjrzyjmy się typowej aplikacji jednostronicowej.

  • Pierwsza strona to formularz rejestracji.
  • Kliknięcie przycisku „Zaloguj się” spowoduje otwarcie formularza logowania.
  • Zarówno formularze rejestracji, jak i logowania zawierają typowe opcje identyfikatora/hasła oraz uwierzytelniania federacyjnego, np. logowania Google i logowania Facebooka.

Za pomocą interfejsu API do zarządzania danymi logowania możesz dodać do witryny takie funkcje jak:

  • Pokaż selektor kont podczas logowania: wyświetla natywny interfejs selektora kont, gdy użytkownik kliknie „Zaloguj się”.
  • Przechowywanie danych logowania: po udanym logowaniu zaproponuj zapisanie danych logowania w menedżerze haseł przeglądarki do późniejszego wykorzystania.
  • Zezwalaj użytkownikowi na automatyczne logowanie: zezwalaj użytkownikowi na ponowne zalogowanie się, jeśli sesja wygasła.
  • Mediate auto sign-in: gdy użytkownik się wyloguje, wyłącz automatyczne logowanie na czas jego następnej wizyty.

Te funkcje możesz wypróbować w witrynie demonstracyjnejprzykładowym kodem.

Pokazuj wybór konta podczas logowania

Po kliknięciu przez użytkownika przycisku „Zaloguj się” i przejściu do formularza logowania możesz użyć funkcji navigator.credentials.get(), aby pobrać informacje o danych logowania. Chrome pokaże interfejs wyboru konta, w którym użytkownik może wybrać konto.

Pojawia się interfejs wyboru konta, na którym użytkownik może wybrać konto, na które chce się zalogować.
Wyświetla się interfejs wyboru konta, w którym użytkownik może wybrać konto, na które chce się zalogować

Pobieranie obiektu danych logowania z hasłem

Aby wyświetlić dane logowania jako opcje konta, użyj password: true.

navigator.credentials.get({
    password: true, // `true` to obtain password credentials
}).then(function(cred) {
    // continuation
    ...

Logowanie się przy użyciu hasła

Gdy użytkownik dokona wyboru konta, funkcja rozpoznawania otrzyma dane logowania do hasła. Możesz go wysłać na serwer za pomocą 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

Logowanie się za pomocą danych logowania sfederowanego

Aby wyświetlać użytkownikom konta z federacją, dodaj opcję federated, która przyjmuje tablicę dostawców tożsamości, do opcji get().

gdy w menedżerze haseł jest zapisanych wiele kont;
Gdy w menedżerze haseł jest zapisanych wiele kont
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
    ...

Możesz sprawdzić właściwość type obiektu danych logowania, aby dowiedzieć się, czy są to dane PasswordCredential (type == 'password') czy FederatedCredential (type == 'federated'). Jeśli dane logowania to FederatedCredential, możesz wywołać odpowiedni interfejs API, korzystając z zawartych w nich informacji.

    });
} 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
Schemat blokowy zarządzania danymi logowania

Przechowywanie danych logowania

Gdy użytkownik loguje się w witrynie za pomocą formularza, możesz użyć funkcji navigator.credentials.store(), aby zapisać dane logowania. Użytkownik zostanie poproszony o zapisanie pliku. W zależności od typu danych logowania użyj funkcji new PasswordCredential() lub new FederatedCredential(), aby utworzyć obiekt danych logowania, który chcesz przechowywać.

Chrome pyta użytkowników, czy chcą zapisać dane logowania (lub dostawcę federacji).
Chrome pyta użytkowników, czy chcą zapisać dane logowania (lub dostawcę federacji)

Tworzenie i przechowywanie danych logowania w postaci hasła na podstawie elementu formularza

Podany niżej kod korzysta z atrybutów autocomplete, aby automatycznie mapować elementy formularza na parametry obiektu 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
});

Tworzenie i przechowywanie danych logowania w ramach federacji

// 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
});
Diagram procesu logowania.

Zezwalanie użytkownikowi na automatyczne logowanie się

Gdy użytkownik opuszcza witrynę i wróci do niej później, sesja może wygasnąć. Nie zmuszaj użytkownika do wpisywania hasła za każdym razem, gdy wraca na stronę. Zezwalanie użytkownikowi na automatyczne logowanie się.

Gdy użytkownik zaloguje się automatycznie, pojawi się powiadomienie.
Gdy użytkownik zaloguje się automatycznie, pojawi się powiadomienie.

Pobieranie obiektu danych logowania

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
    ...
    }
});

Kod powinien wyglądać podobnie do tego, który widzisz w sekcji „Pokaż selektor kont podczas logowania”. Jedyną różnicą jest to, że musisz ustawić unmediated: true.

Spowoduje to natychmiastowe rozwiązanie problemu i udzielenie Ci poświadczeń umożliwiających automatyczne logowanie użytkownika. Spełnia kilka warunków:

  • Użytkownik potwierdził, że zapoznał się z funkcją automatycznego logowania w ramach sekcji powitalnej.
  • Użytkownik zalogował się wcześniej na stronie internetowej za pomocą interfejsu Credential Management API.
  • Użytkownik ma tylko 1 zestaw danych logowania zapisany dla Twojego źródła.
  • Użytkownik nie wylogował się w poprzedniej sesji.

Jeśli którykolwiek z tych warunków nie zostanie spełniony, funkcja zostanie odrzucona.

Diagram przepływu obiektu danych logowania

Pośrednictwo w logowaniu automatycznym

Gdy użytkownik wyloguje się z Twojej witryny, Twoim obowiązkiem jest upewnienie się, że nie zaloguje się automatycznie ponownie. W tym celu interfejs API zarządzania danymi logowania udostępnia mechanizm zwany mediacją. Aby włączyć tryb zapośredniczenia, wywołaj metodę navigator.credentials.requireUserMediation(). Dopóki stan pośrednictwa użytkownika dla źródła jest włączony, funkcja unmediated: true z użyciem navigator.credentials.get() będzie zwracać wartość undefined.

Pośrednictwo w logowaniu automatycznym

navigator.credentials.requireUserMediation();
Schemat blokowy logowania automatycznego

Najczęstsze pytania

Czy kod JavaScript w witrynie może pobrać hasło w postaci zwykłego tekstu? Nie. Hasła możesz uzyskać tylko w ramach usługi PasswordCredential. Nie są one w żaden sposób ujawniane.

Czy można zapisać 3 zbiory cyfr identyfikatora za pomocą interfejsu Credential Management API? Obecnie nie. Chętnie poznamy Twoją opinię na temat specyfikacji.

Czy mogę używać interfejsu Credential Management API w elemencie iframe? Interfejs API jest ograniczony do kontekstów najwyższego poziomu. Wywołania funkcji .get() lub .store() w ramce iframe zostaną natychmiast rozwiązane bez efektu.

Czy mogę zintegrować rozszerzenie do zarządzania hasłami do Chrome z interfejsem Credential Management API? Możesz zastąpić navigator.credentials i podłączyć go do rozszerzenia Chrome, aby uzyskać dane logowania get() lub store().

Zasoby

Więcej informacji o interfejsie Credential Management API znajdziesz w przewodniku integracji.