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
Ta ważna zmiana została wprowadzona w Chrome 57 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.
Hasło musisz zapisać za pomocą funkcji navigator.credentials.store()
, aby po wybraniu przez użytkownika danych logowania przez kliknięcie w oknie dialogowym hasło zostało przekazane i skopiowane do bieżącego źródła.
Zapisze hasło będzie dostępne jako dane logowania w tym samym punkcie początkowym (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.navigator.credentials.get()
przyjmuje teraz typ enummediation
zamiast flagi logicznejunmediated
.requireUserMediation()
został przemianowany napreventSilentAccess()
.Nowa metoda
navigator.credentials.create()
tworzy asynchronicznie obiekty danych logowania.
Wykrywanie funkcji wymaga uwagi
Aby dowiedzieć się, czy jest dostępny interfejs Credential Management API do uzyskiwania dostępu do danych uwierzytelniających opartych na haśle i sfederowanych danych logowania, sprawdź, czy jest dostępny window.PasswordCredential
lub window.FederatedCredential
.
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
Obiekt PasswordCredential
zawiera teraz hasło
Do obsługi haseł w interfejsie Credential Management API zastosowano zachowawcze podejście.
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.
Musiał wysłać wartość skrótu hasła na swój serwer.
Po przeprowadzeniu analizy bezpieczeństwa i stwierdzeniu, że ukrywanie haseł w JavaScript nie zapobiega wszystkim wektorom ataków tak skutecznie, jak byśmy tego oczekiwali, postanowiliśmy wprowadzić zmianę.
Interfejs Credential Management API zawiera teraz nieprzetworzone hasło 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 pokazano w poprzednim przykładzie kodu, lub użycie funkcji XMLHttpRequest
.
navigator.credentials.get()
obsługuje teraz zapośredniczenie enum
Do wersji Chrome 60 funkcja navigator.credentials.get()
przyjmowała 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()
.
W przypadku wartości mediation
wybierz jedną z tych opcji:
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 modułu wyboru konta, który jest odpowiednikiem poprzedniej flagi (unmediated: true
):
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(c => {
// Sign-in
});
Zmieniono nazwę z requireUserMediation()
na preventSilentAccess()
Aby dostosować ją do nowej właściwości mediation
oferowanej w wywołaniu get()
, nazwę metody navigator.credentials.requireUserMediation()
zmieniono 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.