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

Matt Gaunt
Ali Poşet
Ali Polat

Chrome, Web Push API'yi ilk kez desteklediğinde, daha önce Google Cloud Messaging (GCM) olarak bilinen Firebase Cloud Messaging (FCM) push hizmetini kullanıyordu. Özel API'sinin kullanılması gerekir. Bu, Chrome'un Web Push API'sini, Web İtme Protokolü spesifikasyonunun henüz yazıldığı bir zamanda geliştiricilerin kullanımına sunmasına ve Web Aktarma Protokolü'nde bulunmayan bir anda kimlik doğrulaması (iletiyi gönderen kişinin söylediği kişi olduğu anlamına gelir) sağlamasına olanak tanıdı. İyi haberlerim var: Bunların ikisi de artık doğru değil.

FCM / GCM ve Chrome artık standart Web Aktarma Protokolü'nü desteklemektedir. Gönderen kimlik doğrulaması ise VAPID uygulanarak yapılabilir. Bu da web uygulamanızın artık bir "gcm_sender_id" değerine ihtiyaç duymadığı anlamına gelir.

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

FCM, Web Push Protokolü'nü destekler

Biraz bağlamla başlayalım. Web uygulamanız bir push aboneliğine kaydolduğunda, bir push hizmetinin URL'si verilir. Sunucunuz, kullanıcınıza web uygulamanız üzerinden veri göndermek için bu uç noktayı kullanır. VAPID'si olmayan bir kullanıcıya abone olursanız Chrome'da size bir FCM uç noktası verilir. (VAPID'ye daha sonra değineceğiz). FCM'nin Web Push Protokolü'nü desteklemesi için, FCM API isteğinde bulunmadan önce URL'nin sonundan FCM kayıt kimliğini çıkartıp başlığa yerleştirmeniz gerekiyordu. Örneğin, https://android.googleapis.com/gcm/send/ABCD1234 bir FCM uç noktasının kayıt kimliği "ABCD1234" olur.

FCM artık Web Push Protokolü'nü desteklediğine göre, uç noktayı olduğu gibi bırakabilir ve URL'yi Web İtme Protokolü uç noktası olarak kullanabilirsiniz. (Bu şekilde Firefox ve ileride kullanıma sunulacak diğer tüm tarayıcılarla uyumlu olmasını sağlayabilirsiniz.)

VAPID'e geçmeden önce, sunucu kodumuzun FCM uç noktasını doğru şekilde işlediğinden emin olmamız gerekir. Aşağıda, Düğüm'de bir push hizmetine istekte bulunma örneği verilmiştir. FCM için istek başlıklarına API anahtarı eklediğimize dikkat edin. Diğer push hizmeti uç noktaları için buna 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 bir "gcm_sender_id" eklemeniz gerekir. API anahtarı ve gönderen kimliği, istekleri yapan 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'nin API'sinde yapılan bir değişiklik olduğunu, dolayısıyla aboneliklerinizi güncellemeniz gerekmediğini unutmayın. Başlıkları yukarıda gösterildiği gibi tanımlamak için sunucu kodunuzu değiştirmeniz yeterlidir.

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

VAPID, "Voluntary Application Server Identification"ın yeni ve en popüler kısa adıdır. Bu yeni spesifikasyon temel olarak uygulama sunucunuz ile push hizmeti arasındaki bir el sıkışmayı tanımlar ve push hizmetinin, hangi sitenin mesaj gönderdiğini onaylamasına olanak tanır. VAPID ile push mesajı göndermek için FCM'ye özgü adımlardan kaçınabilirsiniz. Artık Firebase projesi, gcm_sender_id veya Authorization başlığına ihtiyacınız yoktur.

İşlem oldukça basittir:

  1. Uygulama sunucunuz bir genel/özel anahtar çifti oluşturur. Ortak anahtar, web uygulamanıza verilir.
  2. Kullanıcı aktarmaları almayı seçtiğinde, ortak anahtarı BEGIN() çağrısının seçenekler nesnesine ekleyin.
  3. Uygulama sunucunuz push mesajı gönderdiğinde ortak anahtarla birlikte imzalı bir JSON Web Jetonu ekleyin.

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

Genel/özel anahtar çifti oluşturma

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

Uygulama sunucuları, P-256 eğrisi üzerinde elips biçimli eğri dijital imza (ECDSA) ile kullanılabilen bir imzalama anahtar çifti oluşturmalı ve sürdürmelidir.

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

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 göndermek üzere abone yapmak için, subscription() yönteminin applicationServerKey parametresini kullanarak ortak anahtarı bir Uint8Array olarak iletmeniz gerekir.

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

Sonuçta ortaya çıkan abonelik nesnesindeki uç noktayı inceleyerek bunun işe yarayıp yaramadığını anlarsınız. Kaynak fcm.googleapis.com ise çalışır durumdadır.

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

Push mesajı gönderme

VAPID kullanarak ileti göndermek için bir Yetkilendirme üst bilgisi ve bir Şifreleme Anahtarı üstbilgisi olmak üzere iki ek HTTP üstbilgisine sahip normal bir Web İletim Protokolü isteği göndermeniz gerekir.

Yetkilendirme üst bilgisi

Authorization üstbilgisi, önünde "WebPush" bulunan imzalı bir JSON Web Token (JWT) şeklindedir.

JWT, gönderen tarafın imzalayabileceği ve alıcı tarafın imzanın beklenen gönderenden geldiğini doğrulayabileceği şekilde, JSON nesnesini ikinci bir tarafla paylaşmanın bir yoludur. JWT'nin yapısı, aralarında tek bir nokta olacak şekilde birleştirilen üç şifrelenmiş dizeden oluşur.

<JWTHeader>.<Payload>.<Signature>

JWT başlığı

JWT Başlığı, imzalama için kullanılan algoritma adını ve jeton türünü içerir. VAPID için bu:

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

Bu, daha sonra base64 URL'si olarak kodlanır ve JWT'nin ilk kısmı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 (sitenizin kaynağı DEĞİL). JavaScript'te, kitleye ulaşmak için aşağıdakileri yapabilirsiniz: const audience = new URL(subscription.endpoint).origin
  • Son Kullanma Tarihi ("exp")
    • Bu, isteğin süresi dolmuş olarak kabul edilmesi gereken saniye sayısıdır. Bu değer, isteğin gönderilmesinden sonraki 24 saat içinde (UTC) ZORUNLUDUR.
  • Konu ("abone")
    • 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.

Yüklenecek örnek bir durum aşağıdaki gibi 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 olarak kodlanmıştır ve JWT'nin ikinci kısmını oluşturur.

İmza

İmza, kodlanmış başlık ve yükün bir noktayla birleştirilip daha önce oluşturduğunuz VAPID özel anahtarı kullanılarak şifrelenmesiyle ortaya çıkar. Sonucun kendisi başlığa bir nokta ile eklenmelidir.

Üstbilgi ve yük JSON nesnelerini alıp bu imzayı oluşturacak çeşitli kitaplıklar olduğundan bunun için bir kod örneği göstermeyeceğiz.

İmzalanmış JWT, başına "WebPush" eklenmiş Yetkilendirme başlığı olarak kullanılır ve aşağıdakine benzer:

WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A

Bu konuda bazı şeylere dikkat edin. Öncelikle, Yetkilendirme başlığı tam anlamıyla "WebPush" kelimesini içerir ve ardından bir boşluk, ardından JWT gelir. Ayrıca JWT başlığını, yükünü ve imzasını ayıran noktalara da dikkat edin.

Şifreleme Anahtarı başlığı

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

p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo

Şifrelenmiş veri içeren bir bildirim gönderirken zaten Crypto-Key üst bilgisini kullanırsınız. Bu nedenle, uygulama sunucusu anahtarını eklemek için yukarıdaki içeriği eklemeden önce noktalı virgül eklemeniz yeterlidir. Bunun sonucunda:

dh=BGEw2wsHgLwzerjvnMTkbKrFRxdmwJ5S_k7zi7A1coR_sVjHmGrlvzYpAT1n4NPbioFlQkIrTNL8EH4V3ZZ4vJE;
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaN

Bu değişikliklerin gerçeği

VAPID ile artık Chrome'da push özelliğini kullanmak için GCM hesabı için kaydolmanıza gerek yoktur. Ayrıca, 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 öncesinde, Android için Opera ve Samsung tarayıcıda yine web uygulaması manifest dosyanızda gcm_sender_id öğesini tanımlamanız ve döndürülecek FCM uç noktasına Yetkilendirme başlığını eklemeniz gerektiğini unutmayın.

VAPID, bu özel gereksinimlere uygun bir çıkış desteği sağlar. VAPID'yi uygularsanız tablo, web push'u destekleyen tüm tarayıcılarda çalışır. VAPID'yi daha fazla tarayıcı desteklediğinden gcm_sender_id öğesinin manifestinizden ne zaman çıkarılacağına karar verebilirsiniz.