Niektóre z opisanych tu aktualizacji zostały omówione w sesji Google I/O: Bezpieczne i bezproblemowe logowanie: utrzymanie zaangażowania użytkowników:
Chrome 57
Ta ważna zmiana została wprowadzona w Chrome 57 w interfejsie Credential Management API.
Dane logowania mogą być udostępniane z innej subdomeny
Chrome może teraz pobrać dane logowania przechowywane w innej subdomenie za pomocą interfejsu Credential Management API.
Jeśli np. hasło jest przechowywane w usłudze login.example.com
, skrypt w 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ą navigator.credentials.store()
, aby gdy użytkownik wybierze dane logowania, klikając okno, zostanie ono przekazane i skopiowane do bieżącego źródła.
Po zapisaniu hasło jest dostępne jako dane logowania w dokładnie tym samym źródle (www.example.com
).
Na poniższym zrzucie ekranu dane logowania przechowywane w systemie login.aliexpress.com
są widoczne dla platformy m.aliexpress.com
i dostępne dla użytkownika:
![Wybór konta wyświetlający dane logowania w wybranej subdomenie](https://developer.chrome.com/static/blog/credential-management-updates/image/account-chooser-showing-s-369ff3f4bb61e.png?authuser=7&hl=pl)
Chrome 60
W Chrome 60 wprowadziliśmy kilka ważnych zmian w interfejsie Credential Management API:
Niestandardowa funkcja
fetch()
nie jest już wymagana do pobierania hasła, dlatego wkrótce zostanie wycofana.navigator.credentials.get()
akceptuje teraz wyliczeniemediation
zamiast flagi wartości logicznejunmediated
.Nazwa użytkownika
requireUserMediation()
została zmieniona napreventSilentAccess()
.Nowa metoda
navigator.credentials.create()
asynchronicznie tworzy obiekty danych logowania.
Wykrywanie funkcji wymaga uwagi
Aby sprawdzić, czy jest dostępny interfejs Credential Management API umożliwiający dostęp do danych logowania sfederowanych i opartych na hasłach, sprawdź dostępność interfejsu window.PasswordCredential
lub window.FederatedCredential
.
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
PasswordCredential
obiekt zawiera teraz hasło
Interfejs Credential Management API stosuje zachowawcze podejście do obsługi haseł.
Ukrywała hasła przed JavaScriptem, umożliwiając programistom wysyłanie obiektu PasswordCredential
bezpośrednio do serwera w celu weryfikacji za pomocą rozszerzenia interfejsu API fetch()
.
Jednak takie podejście spowodowało kilka ograniczeń. Otrzymaliśmy opinie, że deweloperzy nie mogą korzystać z interfejsu API, ponieważ:
Musieli wysłać hasło jako część obiektu JSON.
Musieli przesłać wartość skrótu hasła na swój serwer.
Gdy przeprowadziliśmy analizę zabezpieczeń i zauważyliśmy, że ukrycie haseł z kodu JavaScript nie powstrzymało wszystkich wektorów ataku tak, jak tego oczekiwaliśmy, 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 dostarczyć dane logowania na swój serwer, możesz użyć istniejących 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);
});
Pobieranie niestandardowe zostanie wkrótce wycofane
Aby określić, czy używasz niestandardowej funkcji fetch()
, sprawdź, czy używa ona obiektu PasswordCredential
czy obiektu FederatedCredential
jako wartości właściwości credentials
, np.:
fetch('/signin', {
method: 'POST',
credentials: c
})
Zalecamy użycie zwykłej funkcji fetch()
, jak pokazano w poprzednim przykładzie kodu, lub użycie XMLHttpRequest
.
navigator.credentials.get()
akceptuje teraz zapośredniczenie wyliczeniowe
Do wersji Chrome 60 navigator.credentials.get()
akceptował opcjonalną właściwość unmediated
z flagą wartości logicznej. 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 okna wyboru konta podczas przekazywania danych logowania.
Flaga jest teraz rozszerzona jako zapośredniczenie. Zapośredniczenie użytkownika może nastąpić, gdy:
Użytkownik musi wybrać konto, na które chce się zalogować.
Użytkownik chce zalogować się bezpośrednio po wywołaniu funkcji
navigator.credentials.requireUseMediation()
.
Wybierz jedną z tych opcji dla wartości mediation
:
Wartość: mediation |
Porównanie z flagą wartości logicznej | Sposób działania | |
---|---|---|---|
silent |
Równa się unmediated: true |
Dane logowania zostały zaliczone bez wyświetlania opcji wyboru konta. | |
optional |
Równa się unmediated: false |
Wyświetla wybór konta, jeśli usługa preventSilentAccess() zadzwoniła wcześniej. |
|
required |
Nowa opcja | Zawsze pokazuj wybór konta. Ta opcja jest przydatna, gdy chcesz pozwolić użytkownikowi na przełączanie konta w natywnym oknie wyboru konta. |
W tym przykładzie dane logowania są przekazywane bez wyświetlania funkcji wyboru konta, czyli odpowiednika poprzedniej flagi – unmediated: true
:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
mediation: 'silent'
}).then(c => {
// Sign-in
});
Nazwa tematu zmieniona z requireUserMediation()
na preventSilentAccess()
Aby dopasować ją do nowej właściwości mediation
oferowanej w wywołaniu get()
, nazwa metody navigator.credentials.requireUserMediation()
została zmieniona na navigator.credentials.preventSilentAccess()
.
Metoda ze zmienioną nazwą uniemożliwia przekazywanie danych logowania bez pokazywania opcji wyboru konta (czasami jest wywoływana bez zapośredniczenia użytkownika). Jest to przydatne, gdy użytkownik wylogowuje się z witryny lub wyrejestruje się z niej i nie chce, by przy następnej wizycie automatycznie się z niej logował.
signoutUser();
if (navigator.credentials) {
navigator.credentials.preventSilentAccess();
}
Asynchronicznie twórz obiekty danych logowania przy użyciu nowej metody navigator.credentials.create()
Możesz teraz asynchronicznie tworzyć obiekty danych logowania za pomocą nowej metody navigator.credentials.create()
.
W dalszej części artykułu znajdziesz porównanie metody synchronizacji i asynchronicznej.
Tworzenie obiektu PasswordCredential
Sposób synchronizacji
let c = new PasswordCredential(form);
Podejście asynchroniczne (nowe)
let c = await navigator.credentials.create({
password: form
});
lub
let c = await navigator.credentials.create({
password: {
id: id,
password: password
}
});
Tworzenie obiektu FederatedCredential
Sposób synchronizacji
let c = new FederatedCredential({
id: 'agektmr',
name: 'Eiji Kitamura',
provider: 'https://accounts.google.com',
iconURL: 'https://*****'
});
Podejście asynchroniczne (nowe)
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? Udostępniliśmy przewodnik po migracji, z którego dowiesz się, jak przejść na nową wersję.