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 sayede Chrome, Web Push Protokolü spesifikasyonunun henüz yazılmakta olduğu bir zamanda Web Push API'yi geliştiricilere sunmuş ve daha sonra Web Push Protokolü'nde bulunmayan kimlik doğrulamayı (mesaj gönderenin kim olduğunu söylediği kişi olduğu anlamına gelir) sağlamıştır. İyi bir haberimiz var: Artık bu iki durum da geçerli değil.

FCM / GCM ve Chrome artık standart Web Push Protokolü'nü desteklerken, gönderen kimlik doğrulaması VAPID uygulanarak yapılabilir. Bu da web uygulamanızın artık "gcm_sender_id" değerine ihtiyaç duymayacağı anlamına gelir.

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

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 FCM API isteği göndermeden önce URL'nin sonundaki FCM kayıt kimliğini alıp başlığa eklemeniz 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 üst bilgilerine 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ı için web uygulamanızın manifest.json dosyasına "gcm_sender_id" eklemeniz de gerekir. 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'i kullanıma sunuyoruz

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 projesi, 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 herkese açık anahtarıyla push'e kaydetmek için subscribe() yönteminin applicationServerKey parametresini kullanarak herkese açık anahtarı Uint8Array olarak iletmeniz gerekir.

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

İşlemin işe yarayıp yaramadığını, oluşturulan abonelik nesnesinde uç noktayı inceleyerek anlayabilirsiniz. Köken fcm.googleapis.com ise işlem işe yaramıştı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 noktayla birleştirilmiş üç şifrelenmiş dizedir.

<JWTHeader>.<Payload>.<Signature>

JWT üst bilgisi

JWT üstbilgisinde, imzalama için kullanılan algoritma adı ve jeton türü bulunur. 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, itme hizmetinin iletiyi gönderen kişiyle 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.

Başlık ve yük JSON nesnelerini alıp bu imzayı sizin için oluşturacak birkaç kitaplık olduğundan bununla ilgili bir kod örneği göstermeyeceğim.

İmzalı JWT, "WebPush" ön ekiyle birlikte Authorization başlığı olarak kullanılır ve aşağıdaki gibi görünür:

WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A

Bu konuda dikkat etmeniz gereken birkaç nokta vardır. Öncelikle, Authorization 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.

Crypto-Key üstbilgisi

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 bir noktalı 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 bildirimleri kullanmak için GCM'de bir hesaba kaydolmanız gerekmez. Hem Chrome hem de Firefox'ta kullanıcıları abone etmek ve kullanıcılara mesaj 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.