Web Push Birlikte Çalışabilirliği Kazanır

Matt Gaunt
Joe Medley
Joe Medley

Chrome, Web Push API'yi ilk desteklediğinde eski adıyla Google Cloud Messaging (GCM) olan Firebase Cloud Messaging (FCM) push hizmetini kullanıyordu. Bunun için özel API'sinin kullanılması gerekiyordu. Bu, Chrome'un Web Push API'si spesifikasyonunun hâlâ yazıldığı ve daha sonra, Web Push Protokolü'nün bulunmadığı bir zamanda kimlik doğrulamasını (yani iletiyi gönderen kişi olduğunu söylediği bir kişi) geliştiricilere Web Push API'sini sunmasını sağladı. İyi haber: artık bunların ikisi de doğru değil.

FCM / GCM ve Chrome artık standart Web Push Protokolü'nü desteklemektedir. Ancak gönderen kimlik doğrulaması VAPID uygulanarak gerçekleştirilebilir. Bu, web uygulamanızın artık bir "gcm_sender_id" kimliğine ihtiyacı yoktur.

Bu makalede, öncelikle mevcut sunucu kodunuzu FCM ile Web Push Protokolü'nü kullanacak şekilde nasıl dönüştüreceğinizi açıklayacağım. Şimdi de VAPID'yi hem istemci hem de sunucu kodunuza nasıl uygulayacağınızı göstereceğim.

FCM, Web Push Protokolü'nü destekler

Konuyu biraz bağlam içinde ele alalım. Web uygulamanız bir push aboneliğine kaydolduğunda, push hizmetinin URL'si verilir. Sunucunuz, web uygulamanız aracılığıyla kullanıcınıza veri göndermek için bu uç noktayı kullanır. Chrome'da, bir kullanıcıyı VAPID olmadan abone ederseniz size bir FCM uç noktası verilir. (VAPID'den daha sonra bahsedeceğiz.) FCM, Web Push Protokolü'nü desteklemeden önce, URL'nin sonundan FCM kayıt kimliğini çıkarmanız ve bir FCM API isteği göndermeden önce başlığa yerleştirmeniz gerekiyordu. Örneğin, https://android.googleapis.com/gcm/send/ABCD1234 olan bir FCM uç noktasının kayıt kimliği "ABCD1234" olur.

FCM artık Web Push Protokolü'nü desteklediğinden uç noktayı olduğu gibi bırakabilir ve URL'yi Web Push Protokolü uç noktası olarak kullanabilirsiniz. (Bu, Chrome'u Firefox ve umarım gelecekteki diğer tüm tarayıcılarla uyumlu hale getirir.)

VAPID'e geçmeden önce sunucu kodumuzun FCM uç noktasını doğru şekilde işlediğinden emin olmamız gerekir. Aşağıda, Node'da bir push hizmetine istek gönderme örneği verilmiştir. FCM için API anahtarını istek başlıklarına eklediğimize dikkat edin. Diğer push hizmeti uç noktaları için bu işleme gerek yoktur. 52 sürümünden önceki Chrome, Opera Android ve Samsung Tarayıcı uygulamaları için de web uygulamanızın manifest.json dosyasına bir "gcm_sender_id" eklemeniz zorunludur. API anahtarı ve gönderen kimliği, istekte bulunan sunucunun alıcı kullanıcıya mesaj göndermesine gerçekten izin verilip verilmediğini kontrol etmek için kullanılır.

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

Bunun FCM / GCM API'sinde yapılan bir değişiklik olduğunu unutmayın. Bu nedenle, aboneliklerinizi güncellemeniz gerekmez. Sunucu kodunuzu, üstte gösterildiği gibi üstbilgileri tanımlayacak şekilde değiştirmeniz yeterlidir.

Sunucu tanımlama için VAPID ile tanışın

VAPID, "Voluntary Application Server Identification" (İsteğe Bağlı Uygulama Sunucusu Tanımlaması) için yeni ve havalı kısa adıdır. Bu yeni spesifikasyon, temel olarak uygulama sunucunuz ile push hizmeti arasında bir el sıkışma işlemi tanımlar ve push hizmetinin hangi sitenin mesaj gönderdiğini doğrulamasına olanak tanır. VAPID ile push mesajı göndermek için FCM'ye özgü adımları atlayabilirsiniz. Artık Firebase projesine, gcm_sender_id veya Authorization başlığına ihtiyacınız yok.

Süreç oldukça basittir:

  1. Uygulama sunucunuz bir herkese açık/özel anahtar çifti oluşturur. Ortak anahtar, web uygulamanıza verilir.
  2. Kullanıcı push bildirimleri almayı seçtiğinde, herkese açık anahtarı subscribe() çağrısının options nesnesine ekleyin.
  3. Uygulama sunucunuz bir push mesajı gönderirken ortak anahtarla birlikte imzalı bir JSON Web jetonu ekleyin.

Bu adımları ayrıntılı olarak inceleyelim.

Ortak/özel anahtar çifti oluşturma

Şifreleme konusunda çok kötüyüm. Bu nedenle, VAPID herkese açık/gizli anahtarlarının biçimiyle ilgili spesifikasyondaki ilgili bölümü burada bulabilirsiniz:

Uygulama sunucuları, P-256 eğrisi üzerinde eliptik eğri dijital imzası (ECDSA) ile kullanılabilen bir imzalama anahtar çifti oluşturmalı ve bu anahtarı muhafaza etmelidir.

Bunu nasıl yapacağınızı web-push düğüm kitaplığında görebilirsiniz:

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

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

Ortak anahtarla abone olma

Bir Chrome kullanıcısını VAPID ortak anahtarıyla push bildirimine abone olmak için abone olma() yönteminin applicationServerKey parametresini kullanarak ortak anahtarı Uint8Array olarak iletmeniz gerekir.

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

İşlemin çalışıp çalışmadığını, oluşturulan abonelik nesnesinde uç noktayı inceleyerek anlayabilirsiniz. Köken fcm.googleapis.com ise işlem çalışmaktadır.

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

Push mesajı gönderme

VAPID'i kullanarak mesaj göndermek için iki ek HTTP üst bilgisi içeren normal bir Web Push Protokolü isteği göndermeniz gerekir: Authorization (Yetkilendirme) üst bilgisi ve Crypto-Key (Şifre Anahtarı) üst bilgisi.

Yetkilendirme üstbilgisi

Authorization başlığı, önünde "WebPush" bulunan imzalı bir JSON Web Jetonu (JWT)'dur.

JWT, bir JSON nesnesini ikinci bir tarafla paylaşmanın bir yoludur. Bu yöntemde, gönderen taraf nesneyi imzalar ve alıcı taraf, imzanın beklenen gönderenden geldiğini doğrulayabilir. JWT'nin yapısı, aralarında tek bir nokta bulunan ve şifrelenmiş üç dizeden oluşur.

<JWTHeader>.<Payload>.<Signature>

JWT üst bilgisi

JWT üstbilgisi, imzalama için kullanılan algoritma adını ve jeton türünü içerir. VAPID için bu şu şekilde olmalıdır:

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

Bu, daha sonra base64 URL kodlamasıyla kodlanır ve JWT'nin ilk bölümünü oluşturur.

Yük

Yük, aşağıdakileri içeren başka bir JSON nesnesidir:

  • Kitle ("aud")
    • Bu, push hizmetinin kaynağıdır (SİTENİZİN kaynağı DEĞİLDİR). JavaScript'te kitleyi almak için şunları yapabilirsiniz: const audience = new URL(subscription.endpoint).origin
  • Geçerlilik Bitiş Zamanı ("exp")
    • Bu, isteğin süresi dolmuş olarak kabul edilmesi için geçmesi gereken saniye sayısıdır. Bu işlem, UTC'de isteğin gönderilmesinden sonraki 24 saat içinde GEREKIR.
  • Konu ("sub")
    • Konu, bir URL veya mailto: URL'si olmalıdır. Bu, push hizmetinin mesajı gönderenle iletişime geçmesi gerektiğinde bir iletişim noktası sağlar.

Örnek bir yük şu şekilde görünebilir:

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

Bu JSON nesnesi, base64 URL kodlamasıyla kodlanır ve JWT'nin ikinci bölümünü oluşturur.

İmza

İmza, kodlanmış üstbilginin ve yükün bir noktayla birleştirilmesinin ve ardından sonucun daha önce oluşturduğunuz VAPID özel anahtarı kullanılarak şifrelenmesinin sonucudur. Sonuç, başlığa noktayla eklenmelidir.

Üstbilgiyi ve yük JSON nesnelerini alıp sizin için bu imzayı oluşturan çeşitli kitaplıklar bulunduğundan bununla ilgili bir kod örneği göstermeyeceğim.

İmzalanmış JWT, Yetkilendirme üst bilgisi olarak kullanılır ve başına "WebPush" eklenir ve bu kod aşağıdaki gibi görünür:

WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A

Bu konuda dikkat etmeniz gereken birkaç nokta vardır. Öncelikle, Yetkilendirme başlığı tam anlamıyla "WebPush" kelimesini içerir ve ardından bir boşluk ve JWT gelmelidir. Ayrıca JWT başlığını, yükünü ve imzasını ayıran noktaları da görebilirsiniz.

Şifreleme Anahtarı başlığı

Yetkilendirme başlığının yanı sıra VAPID ortak anahtarınızı, p256ecdsa= önek eklenmiş base64 URL kodlu bir dize olarak Crypto-Key başlığına eklemeniz gerekir.

p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo

Şifrelenmiş veriler içeren bir bildirim gönderirken zaten Crypto-Key üstbilgisini kullanıyorsunuzdur. Bu nedenle, uygulama sunucusu anahtarını eklemek için yukarıdaki içeriği eklemeden önce virgül eklemeniz yeterlidir. Böylece aşağıdaki sonuç elde edilir:

dh=BGEw2wsHgLwzerjvnMTkbKrFRxdmwJ5S_k7zi7A1coR_sVjHmGrlvzYpAT1n4NPbioFlQkIrTNL8EH4V3ZZ4vJE;
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaN

Bu değişikliklerin gerçekliği

VAPID ile artık Chrome'da push bildirimlerini kullanmak için GCM'ye hesap açmanıza gerek yoktur. Hem Chrome'da hem de Firefox'ta bir kullanıcıya abone olmak ve bir kullanıcıya ileti göndermek için aynı kod yolunu kullanabilirsiniz. Her ikisi de standartlara uygundur.

Chrome 51 ve önceki sürümlerde, Android için Opera ve Samsung tarayıcıda web uygulaması manifestinizde gcm_sender_id değerini tanımlamaya ve döndürülecek FCM uç noktasına Authorization başlığını eklemeye devam etmeniz gerektiğini unutmayın.

VAPID, bu tescilli şartlardan geçiş imkanı sunar. VAPID'i uygularsanız web push'i destekleyen tüm tarayıcılarda çalışır. VAPID'i destekleyen tarayıcı sayısı arttıkça gcm_sender_id öğesini manifest dosyanızdan ne zaman kaldıracağınıza karar verebilirsiniz.