Niektóre z opisanych tu zmian zostały omówione podczas sesji na konferencji Google I/O Bezpieczne i płynne logowanie: jak utrzymać zaangażowanie użytkowników:
Chrome 57
W Chrome 57 wprowadzono tę ważną zmianę w interfejsie Credential Management API.
Dane logowania można udostępnić z innej subdomeny
Chrome może teraz pobierać dane logowania zapisane w innej subdomenie za pomocą interfejsu Credential Management API.
Jeśli np. hasło jest zapisane w koncie login.example.com
, skrypt na koncie www.example.com
może wyświetlić je jako jeden z elementów konta w oknie wyboru konta.
Musisz wyraźnie zapisać hasło za pomocą funkcji navigator.credentials.store()
, aby gdy użytkownik wybierze dane logowania, klikając okno dialogowe, hasło zostało przekazane i skopiowane do bieżącego źródła.
Po zapisaniu hasło jest dostępne jako dane logowania w tym samym źródle www.example.com
.
Na poniższym zrzucie ekranu informacje o kwalifikacjach przechowywane w sekcji login.aliexpress.com
są widoczne dla m.aliexpress.com
i dostępne dla użytkownika:
Chrome 60
W Chrome 60 wprowadzono kilka ważnych zmian w interfejsie Credential Management API:
Funkcja niestandardowa
fetch()
nie jest już potrzebna do pobierania hasła, dlatego wkrótce zostanie wycofana.Parametr
navigator.credentials.get()
przyjmuje teraz typ enummediation
zamiast flagi logicznejunmediated
.requireUserMediation()
został przemianowany napreventSilentAccess()
.Nowa metoda
navigator.credentials.create()
asychronicznie tworzy obiekty danych logowania.
Wykrywanie funkcji wymaga uwagi
Aby sprawdzić, czy interfejs Credential Management API jest dostępny dla haseł i poświadczeń uwierzytelniania federacyjnego, sprawdź, czy jest dostępna usługa window.PasswordCredential
lub window.FederatedCredential
.
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
Obiekt PasswordCredential
zawiera teraz hasło
Interfejs Credential Management API stosował konserwatywne podejście do obsługi haseł.
Ukrywało hasła przed JavaScriptem, wymagając od deweloperów wysyłania obiektu PasswordCredential
bezpośrednio na serwer w celu sprawdzenia za pomocą rozszerzenia interfejsu API fetch()
.
Takie podejście wiązało się jednak z pewnymi ograniczeniami. Otrzymaliśmy informację, że deweloperzy nie mogli korzystać z interfejsu API, ponieważ:
Hasło musi być wysyłane jako część obiektu JSON.
Musieli wysłać na swój serwer wartość hasha hasła.
Po przeprowadzeniu analizy bezpieczeństwa i stwierdzeniu, że ukrywanie haseł w JavaScript nie zapobiegało wszystkim wektorom ataków tak skutecznie, jak mieliśmy nadzieję, postanowiliśmy wprowadzić zmianę.
Interfejs Credential Management API zawiera teraz hasło w postaci zwykłego tekstu w zwróconym obiekcie danych logowania, dzięki czemu masz do niego dostęp w postaci zwykłego tekstu. Aby przekazać informacje o danych logowania na serwer, możesz użyć dotychczasowych metod:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(passwordCred => {
if (passwordCred) {
let form = new FormData();
form.append('email', passwordCred.id);
form.append('password', passwordCred.password);
form.append('csrf_token', csrf_token);
return fetch('/signin', {
method: 'POST',
credentials: 'include',
body: form
});
} else {
// Fallback to sign-in form
}
}).then(res => {
if (res.status === 200) {
return res.json();
} else {
throw 'Auth failed';
}
}).then(profile => {
console.log('Auth succeeded', profile);
});
Wybieranie niestandardowe zostanie wkrótce wycofane
Aby sprawdzić, czy używasz niestandardowej funkcji fetch()
, sprawdź, czy używa ona obiektu PasswordCredential
lub FederatedCredential
jako wartości właściwości credentials
, na przykład:
fetch('/signin', {
method: 'POST',
credentials: c
})
Zalecamy użycie zwykłej funkcji fetch()
, jak w poprzednim przykładzie kodu, lub użycie funkcji XMLHttpRequest
.
navigator.credentials.get()
obsługuje teraz zapośredniczenie enum
Do wersji Chrome 60 element navigator.credentials.get()
akceptował opcjonalną właściwość unmediated
z flagą logiczną. Na przykład:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
unmediated: true
}).then(c => {
// Sign-in
});
Ustawienie unmediated: true
uniemożliwia przeglądarce wyświetlanie selektora kont podczas przekazywania danych logowania.
Flaga jest teraz rozszerzona o zapośredniczenie. Mediacja użytkownika może się zdarzyć, gdy:
Użytkownik musi wybrać konto, na które chce się zalogować.
Użytkownik chce się zalogować po wywołaniu funkcji
navigator.credentials.requireUseMediation()
.
Wybierz jedną z tych opcji dla wartości mediation
:
Wartość: mediation |
W porównaniu z flagą logiczną | Zachowanie | |
---|---|---|---|
silent |
Równa się unmediated: true |
Dane logowania zostały przekazane bez wyświetlenia selektora kont. | |
optional |
Równa się unmediated: false |
Wyświetla selektor kont, jeśli preventSilentAccess() został wywołany wcześniej. |
|
required |
Nowa opcja | Zawsze pokazuj selektor kont. Przydatne, gdy chcesz umożliwić użytkownikowi przełączanie kont za pomocą domyślnego okna wyboru konta. |
W tym przykładzie dane logowania są przekazywane bez wyświetlania selektora kont, co jest równoznaczne z poprzednią flagą: unmediated: true
.
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(c => {
// Sign-in
});
Zmieniono nazwę użytkownika z requireUserMediation()
na preventSilentAccess()
Aby dostosować ją do nowej właściwości mediation
oferowanej w wywołaniu get()
, nazwę metody navigator.credentials.requireUserMediation()
zmieniliśmy na navigator.credentials.preventSilentAccess()
.
Przemianowana metoda zapobiega przekazywaniu danych logowania bez wyświetlania selektora kont (czasami wywoływanego bez pośrednictwa użytkownika). Jest to przydatne, gdy użytkownik wyloguje się z witryny lub wyrejestruje się z niej i nie chce, aby przy następnej wizycie nastąpiło automatyczne zalogowanie.
signoutUser();
if (navigator.credentials) {
navigator.credentials.preventSilentAccess();
}
Tworzenie obiektów danych logowania w tle za pomocą nowej metody navigator.credentials.create()
Teraz możesz asynchronicznie tworzyć obiekty danych logowania za pomocą nowej metody navigator.credentials.create()
.
Czytaj dalej, aby porównać podejścia synchroniczne i asynchroniczne.
Tworzenie obiektu PasswordCredential
Podejście do synchronizacji
let c = new PasswordCredential(form);
Podejście asynchroniczne (nowość)
let c = await navigator.credentials.create({
password: form
});
lub
let c = await navigator.credentials.create({
password: {
id: id,
password: password
}
});
Tworzenie obiektu FederatedCredential
Podejście do synchronizacji
let c = new FederatedCredential({
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
});
Podejście asynchroniczne (nowość)
let c = await navigator.credentials.create({
federated: {
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
}
});
Przewodnik po migracji
Czy masz już implementację interfejsu Credential Management API? Aby przejść na nową wersję, możesz skorzystać z przewodnika po migracji.