Zalety interoperacyjności Web Push Interop

Joe Medley
Joe Medley

Gdy Chrome po raz pierwszy obsługiwał interfejs Web Push API, korzystał z usługi push Firebase Cloud Messaging (FCM), która wcześniej była znana jako Google Cloud Messaging (GCM). Wymaga to użycia zastrzeżonego interfejsu API. Dzięki temu Chrome mogła udostępnić interfejs Web Push API deweloperom w czasie, gdy specyfikacja protokołu Web Push była jeszcze tworzona, a później zapewnić uwierzytelnianie (czyli potwierdzenie tożsamości nadawcy wiadomości) w czasie, gdy protokół Web Push nie miał jeszcze tej funkcji. Dobra wiadomość: żadna z tych rzeczy nie jest już prawdziwa.

FCM / GCM i Chrome obsługują teraz standardowy protokół Web Push, a uwierzytelnianie nadawcy można uzyskać dzięki wdrożeniu VAPID, co oznacza, że Twoja aplikacja internetowa nie musi już zawierać identyfikatora „gcm_sender_id”.

W tym artykule najpierw opiszę, jak przekonwertować dotychczasowy kod serwera, aby używać protokołu Web Push w połączeniu z FCM. Następnie pokażę Ci, jak zaimplementować VAPID w kodzie klienta i serwera.

FCM obsługuje protokół Web Push Protocol

Zacznijmy od kontekstu. Gdy aplikacja internetowa rejestruje się w subskrypcji powiadomień push, otrzymuje adres URL usługi powiadomień push. Serwer będzie używać tego punktu końcowego, by wysyłać dane do użytkownika przez aplikację internetową. W Chrome otrzymasz punkt końcowy FCM, jeśli zasubskrybujesz użytkownika bez VAPID. (omówimy je później). Zanim FCM obsługiwał protokół Web Push, przed wysłaniem żądania do interfejsu FCM API należało wyodrębnić identyfikator rejestracji FCM z końca adresu URL i umieścić go w nagłówku. Na przykład punkt końcowy FCM o adresie https://android.googleapis.com/gcm/send/ABCD1234 miałby identyfikator rejestracji „ABCD1234”.

Ponieważ FCM obsługuje protokół Web Push, możesz pozostawić punkt końcowy w swoim pierwotnym stanie i używać adresu URL jako punktu końcowego protokołu Web Push. Dzięki temu będzie ona zgodna z przeglądarką Firefox i prawdopodobnie każdą inną przeglądarką.

Zanim przejdziemy do VAPID, musimy się upewnić, że kod serwera poprawnie obsługuje punkt końcowy FCM. Poniżej znajdziesz przykład wysyłania żądania do usługi push w Node. Pamiętaj, że w przypadku FCM dodajemy klucz interfejsu API do nagłówków żądania. W przypadku innych punktów końcowych usługi push nie jest to wymagane. W przypadku Chrome w wersji starszej niż 52, Opery na Androida i przeglądarki Samsunga nadal musisz też dodać parametr „gcm_sender_id” w pliku manifest.json aplikacji internetowej. Klucz interfejsu API i identyfikator nadawcy służą do sprawdzania, czy serwer przesyłający żądania ma rzeczywiście uprawnienia do wysyłania wiadomości do użytkownika odbierającego.

const headers = new Headers();
// 12-hour notification time to live.
headers.append('TTL', 12 * 60 * 60);
// Assuming no data is going to be sent
headers.append('Content-Length', 0);

// Assuming you're not using VAPID (read on), this
// proprietary header is needed
if(subscription.endpoint
    .indexOf('https://android.googleapis.com/gcm/send/') === 0) {
    headers.append('Authorization', 'GCM_API_KEY');
}

fetch(subscription.endpoint, {
    method: 'POST',
    headers: headers
})
.then(response => {
    if (response.status !== 201) {
    throw new Error('Unable to send push message');
    }
});

Pamiętaj, że jest to zmiana interfejsu FCM / GCM, więc nie musisz aktualizować subskrypcji. Zamiast tego zmień kod serwera, aby zdefiniować nagłówki zgodnie z opisem powyżej.

Przedstawiamy VAPID do identyfikacji serwerów

VAPID to nowa, krótka nazwa identyfikacji serwera aplikacji na żądanie. Ta nowa specyfikacja definiuje w podstawie procedurę uzgadniania połączenia między serwerem aplikacji a usługą przesyłania powiadomień push i pozwala usłudze przesyłania powiadomień push potwierdzić, która witryna wysyła powiadomienia. Dzięki VAPID możesz pominąć kroki związane z wysyłaniem wiadomości push w ramach FCM. Nie potrzebujesz już projektu Firebase, nagłówka gcm_sender_id ani Authorization.

Proces jest dość prosty:

  1. Serwer aplikacji tworzy parę kluczy publiczno-prywatnych. Klucz publiczny jest przekazywany aplikacji internetowej.
  2. Gdy użytkownik zdecyduje się na otrzymywanie powiadomień push, dodaj klucz publiczny do obiektu opcji wywołania subscribe().
  3. Gdy serwer aplikacji wysyła komunikat push, dołącz podpisany token sieciowy JSON wraz z kluczem publicznym.

Przyjrzyjmy się tym krokom bardziej szczegółowo.

Tworzenie pary kluczy (publicznego i prywatnego)

Nie znam się na szyfrowaniu, więc poniżej podaję odpowiednią sekcję specyfikacji dotyczącej formatu kluczy publicznych i prywatnych VAPID:

Serwery aplikacji MUSZĄ generować i utrzymywać parę kluczy podpisywania, której można używać z podpisem cyfrowym krzywych eliptycznych (ECDSA) na krzywej P-256.

Więcej informacji znajdziesz w bibliotece węzła web-push:

function generateVAPIDKeys() {
    var curve = crypto.createECDH('prime256v1');
    curve.generateKeys();

    return {
    publicKey: curve.getPublicKey(),
    privateKey: curve.getPrivateKey(),
    };
}

Subskrybowanie za pomocą klucza publicznego

Aby zasubskrybować użytkownika Chrome do otrzymywania powiadomień push za pomocą klucza publicznego VAPID, musisz przekazać klucz publiczny jako tablicę Uint8 za pomocą parametru applicationServerKey metody subscribe().

const publicKey = new Uint8Array([0x4, 0x37, 0x77, 0xfe, . ]);
serviceWorkerRegistration.pushManager.subscribe(
    {
    userVisibleOnly: true,
    applicationServerKey: publicKey
    }
);

Aby sprawdzić, czy udało się to zrobić, sprawdź punkt końcowy w wynikającym obiekcie subskrypcji. Jeśli źródło to fcm.googleapis.com, oznacza to, że wszystko działa prawidłowo.

https://fcm.googleapis.com/fcm/send/ABCD1234

Wysyłam wiadomość push

Aby wysłać wiadomość za pomocą VAPID, musisz przesłać zwykłe żądanie Web Push Protocol z 2 dodatkowymi nagłówkami HTTP: nagłówkiem Authorization i nagłówkiem Crypto-Key.

Nagłówek autoryzacji

Nagłówek Authorization to podpisany token sieciowy JSON (JWT) z dodatkiem prefiksu „WebPush”.

Token JWT to sposób udostępniania obiektu JSON drugiej stronie w taki sposób, aby strona wysyłająca mogła go podpisać, a strona odbierająca mogła zweryfikować podpis, aby upewnić się, że pochodzi on od oczekiwanego nadawcy. Struktura tokena JWT to 3 zaszyfrowane ciągi znaków połączone jedną kropką.

<JWTHeader>.<Payload>.<Signature>

Nagłówek JWT

Nagłówek JWT zawiera nazwę algorytmu używanego do podpisywania i typ tokena. W przypadku VAPID musi to być:

{
    "typ": "JWT",
    "alg": "ES256"
}

Następnie jest on kodowany w standardzie base64url i stanowi pierwszą część tokena JWT.

Ładunek

Ładunek to kolejny obiekt JSON zawierający:

  • Odbiorcy („aud”):
    • To źródło usługi push (NIE źródło Twojej witryny). Aby uzyskać listę odbiorców, możesz wykonać w JavaScript te czynności: const audience = new URL(subscription.endpoint).origin
  • Okres ważności („exp”)
    • Jest to liczba sekund, po których żądanie zostanie uznane za wygasłe. MUSI to nastąpić w ciągu 24 godzin od wysłania prośby (według czasu UTC).
  • Temat („sub”)
    • Temat musi być adresem URL lub adresem URL mailto:. Jest to punkt kontaktowy na wypadek, gdyby usługa push musiała skontaktować się z nadawcą wiadomości.

Przykładowy ładunek może wyglądać tak:

{
    "aud": "http://push-service.example.com",
    "exp": Math.floor((Date.now() / 1000) + (12 * 60 * 60)),
    "sub": "mailto: my-email@some-url.com"
}

Ten obiekt JSON jest zakodowany w formacie base64 i stanowi drugą część tokena JWT.

Podpis

Podpis jest wynikiem złączenia zakodowanego nagłówka i ładunku za pomocą kropki, a następnie zaszyfrowania tego wyniku za pomocą utworzonego wcześniej klucza prywatnego VAPID. Sam wynik powinien być dołączony do nagłówka kropką.

Nie pokażę przykładu kodu, ponieważ istnieje wiele bibliotek, które pobierają obiekty nagłówka i ładunku JSON i generują na ich podstawie podpis.

Podpisany token JWT jest używany jako nagłówek Authorization z dołączonym do niego ciągiem „WebPush” i wygląda mniej więcej tak:

WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A

Zwróć uwagę na kilka kwestii. Pierwszy nagłówek Authorization dosłownie zawiera słowo „WebPush”. Po nim powinien znajdować się spacja, a po nim token JWT. Zwróć też uwagę na kropki oddzielające nagłówek, ładunek i podpis JWT.

Nagłówek Crypto-Key

Oprócz nagłówka autoryzacji musisz dodać do nagłówka Crypto-Key klucz publiczny VAPID w postaci ciągu zakodowanego w formacie base64 z dołączonym przedrostkiem p256ecdsa=.

p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo

Gdy wysyłasz powiadomienie z zaszyfrowanymi danymi, używasz już nagłówka Crypto-Key. Dlatego, aby dodać klucz serwera aplikacji, musisz tylko przed dodaniem powyższej treści dodać średnik. Efekt:

dh=BGEw2wsHgLwzerjvnMTkbKrFRxdmwJ5S_k7zi7A1coR_sVjHmGrlvzYpAT1n4NPbioFlQkIrTNL8EH4V3ZZ4vJE;
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaN

Realizacja tych zmian

Dzięki VAPID nie musisz już rejestrować konta w GCM, aby korzystać z powiadomień push w Chrome. Możesz też używać tego samego kodu do rejestrowania użytkownika i wysyłania mu wiadomości zarówno w Chrome, jak i w Firefoksie. Oba są zgodne ze standardami.

Pamiętaj, że w Chrome 51 i starszych wersjach, a także w Opera na Androida i w przeglądarce Samsung nadal musisz zdefiniować gcm_sender_idw manifeście aplikacji internetowej i dodać nagłówek Authorization do zwracanego punktu końcowego FCM.

VAPID zapewnia wyjście z tych zastrzeżonych wymagań. Jeśli wdrożysz VAPID, będzie on działać we wszystkich przeglądarkach, które obsługują web push. Gdy więcej przeglądarek będzie obsługiwać VAPID, możesz zdecydować, kiedy usunąć gcm_sender_id z pliku manifestu.