قابلیت همکاری Web Push برنده است

هنگامی که کروم برای اولین بار از Web Push API پشتیبانی کرد، بر روی Firebase Cloud Messaging (FCM) که قبلاً Google Cloud Messaging (GCM) نامیده می‌شد، متکی بود. این نیاز به استفاده از API اختصاصی آن دارد. این به Chrome اجازه داد تا Web Push API را در زمانی که مشخصات پروتکل Web Push هنوز در حال نگارش بود در دسترس توسعه دهندگان قرار دهد و بعداً احراز هویت (به این معناست که فرستنده پیام همان کسی است که آنها می‌گویند) در زمانی که پروتکل Web Push فاقد آن بود. خبر خوب: هیچ کدام از اینها دیگر درست نیست.

FCM/GCM و Chrome اکنون از پروتکل Web Push استاندارد پشتیبانی می‌کنند، در حالی که احراز هویت فرستنده را می‌توان با پیاده‌سازی VAPID به دست آورد، به این معنی که برنامه وب شما دیگر به «gcm_sender_id» نیاز ندارد.

در این مقاله، ابتدا قصد دارم نحوه تبدیل کد سرور موجود خود را برای استفاده از پروتکل فشار وب با FCM شرح دهم. در مرحله بعد، من به شما نشان خواهم داد که چگونه VAPID را در کد مشتری و سرور خود پیاده سازی کنید.

FCM از پروتکل Web Push پشتیبانی می کند

بیایید با یک زمینه کوچک شروع کنیم. هنگامی که برنامه وب شما برای اشتراک پوش ثبت نام می کند، URL یک سرویس فشار داده می شود. سرور شما از این نقطه پایانی برای ارسال داده به کاربر از طریق برنامه وب شما استفاده می کند. اگر کاربر بدون VAPID مشترک شوید، در Chrome یک نقطه پایانی FCM به شما داده می شود. (ما بعداً VAPID را پوشش خواهیم داد). قبل از اینکه FCM از پروتکل Web Push پشتیبانی کند، باید شناسه ثبت FCM را از انتهای URL استخراج کرده و قبل از درخواست FCM API در هدر قرار دهید. برای مثال، یک نقطه پایانی FCM از https://android.googleapis.com/gcm/send/ABCD1234 ، دارای شناسه ثبت «ABCD1234» است.

اکنون که FCM از پروتکل Web Push پشتیبانی می کند، می توانید نقطه پایانی را دست نخورده رها کنید و از URL به عنوان نقطه پایانی پروتکل فشار وب استفاده کنید. (این آن را با فایرفاکس و امیدواریم هر مرورگر دیگری در آینده هماهنگ می کند.)

قبل از اینکه وارد VAPID شویم، باید مطمئن شویم که کد سرور ما به درستی نقطه پایانی FCM را مدیریت می کند. در زیر نمونه ای از درخواست به سرویس پوش در Node آورده شده است. توجه داشته باشید که برای FCM ما کلید API را به هدرهای درخواست اضافه می کنیم. برای سایر نقاط پایانی سرویس فشار، این مورد نیاز نخواهد بود. برای Chrome قبل از نسخه 52، Opera Android و مرورگر سامسونگ، همچنان باید یک "gcm_sender_id" را در manifest.json برنامه وب خود اضافه کنید. کلید API و شناسه فرستنده برای بررسی اینکه آیا سرور درخواست کننده واقعاً مجاز به ارسال پیام به کاربر گیرنده است یا خیر استفاده می شود.

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

به یاد داشته باشید، این یک تغییر در API FCM / GCM است، بنابراین نیازی به به روز رسانی اشتراک های خود ندارید، فقط کد سرور خود را تغییر دهید تا هدرها را مطابق شکل بالا تعریف کنید.

معرفی VAPID برای شناسایی سرور

VAPID نام کوتاه جدید جالب برای " شناسایی سرور برنامه داوطلبانه " است. این مشخصات جدید اساساً یک دست دادن بین سرور برنامه شما و سرویس فشار را تعریف می کند و به سرویس فشار اجازه می دهد تا تأیید کند که کدام سایت پیام ارسال می کند. با VAPID می توانید از مراحل خاص FCM برای ارسال پیام فشار اجتناب کنید. دیگر نیازی به پروژه Firebase، gcm_sender_id یا هدر Authorization ندارید.

فرآیند بسیار ساده است:

  1. سرور برنامه شما یک جفت کلید عمومی/خصوصی ایجاد می کند. کلید عمومی به برنامه وب شما داده می شود.
  2. هنگامی که کاربر دریافت فشارها را انتخاب می کند، کلید عمومی را به شی گزینه های فراخوانی subscribe() اضافه کنید.
  3. هنگامی که سرور برنامه شما یک پیام فشار ارسال می کند، یک نشانه وب JSON امضا شده به همراه کلید عمومی اضافه کنید.

بیایید این مراحل را با جزئیات بررسی کنیم.

یک جفت کلید عمومی/خصوصی ایجاد کنید

من در رمزگذاری وحشتناک هستم، بنابراین در اینجا بخش مربوطه از مشخصات مربوط به فرمت کلیدهای عمومی / خصوصی VAPID است:

سرورهای برنامه باید یک جفت کلید امضا قابل استفاده با امضای دیجیتال منحنی بیضوی (ECDSA) روی منحنی P-256 ایجاد و نگهداری کنند.

می توانید نحوه انجام این کار را در کتابخانه web-push node مشاهده کنید:

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

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

اشتراک با کلید عمومی

برای اشتراک کاربر کروم برای فشار با کلید عمومی VAPID، باید کلید عمومی را به عنوان Uint8Array با استفاده از پارامتر applicationServerKey متد subscribe() ارسال کنید.

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

با بررسی نقطه پایانی در شیء اشتراک به دست آمده می‌دانید که آیا کار کرده است، اگر مبدا fcm.googleapis.com باشد، کار می‌کند.

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

ارسال پیام فشار

برای ارسال پیام با استفاده از VAPID، باید یک درخواست پروتکل Web Push معمولی با دو هدر HTTP اضافه کنید: یک هدر مجوز و یک هدر کلید رمزنگاری.

سرصفحه مجوز

هدر Authorization یک نشانه وب JSON (JWT) است که در مقابل آن "WebPush" قرار دارد.

JWT روشی برای به اشتراک گذاری یک شی JSON با شخص دوم است به گونه ای که طرف فرستنده بتواند آن را امضا کند و طرف گیرنده بتواند تأیید کند که امضا از فرستنده مورد انتظار است. ساختار یک JWT سه رشته رمزگذاری شده است که با یک نقطه بین آنها به هم متصل شده اند.

<JWTHeader>.<Payload>.<Signature>

هدر JWT

سربرگ JWT شامل نام الگوریتم مورد استفاده برای امضا و نوع توکن است. برای VAPID باید این باشد:

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

سپس این نشانی اینترنتی base64 کدگذاری می شود و اولین قسمت JWT را تشکیل می دهد.

ظرفیت ترابری

Payload یکی دیگر از شی های JSON است که شامل موارد زیر است:

  • مخاطب ("aud")
    • این منشاء سرویس فشار ( نه مبدا سایت شما) است. در جاوا اسکریپت، می‌توانید کارهای زیر را برای به دست آوردن مخاطب انجام دهید: const audience = new URL(subscription.endpoint).origin
  • زمان انقضا ("انقضا")
    • این تعداد ثانیه هایی است که تا زمانی که درخواست منقضی شده در نظر گرفته شود. این باید ظرف 24 ساعت پس از درخواست، در UTC باشد.
  • موضوع ("زیر")
    • موضوع باید URL یا mailto: URL باشد. در صورتی که سرویس فشار نیاز به تماس با فرستنده پیام داشته باشد، این یک نقطه تماس را فراهم می کند.

یک بار نمونه می تواند به شکل زیر باشد:

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

این شی JSON کد شده با URL base64 است و قسمت دوم JWT را تشکیل می دهد.

امضا

امضا نتیجه پیوستن سرصفحه و محموله رمزگذاری شده با یک نقطه و سپس رمزگذاری نتیجه با استفاده از کلید خصوصی VAPID است که قبلا ایجاد کردید. خود نتیجه باید با یک نقطه به سربرگ اضافه شود.

من قصد ندارم یک نمونه کد برای این کار نشان دهم زیرا تعدادی کتابخانه وجود دارد که هدر و بارگذاری اشیاء JSON را می گیرند و این امضا را برای شما تولید می کنند.

JWT امضا شده به عنوان سربرگ مجوز استفاده می شود که "WebPush" به آن اضافه شده است و چیزی شبیه به زیر خواهد بود:

WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A

به چند نکته در این مورد توجه کنید. ابتدا، هدر Authorization به معنای واقعی کلمه حاوی کلمه "WebPush" است و باید با یک فاصله و سپس JWT دنبال شود. همچنین به نقاط جداکننده هدر JWT، بار محموله و امضا توجه کنید.

هدر Crypto-Key

علاوه بر سرصفحه Authorization، باید کلید عمومی VAPID خود را به عنوان یک رشته کد شده url base64 با p256ecdsa= به هدر Crypto-Key اضافه کنید.

p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo

هنگامی که یک اعلان با داده‌های رمزگذاری شده ارسال می‌کنید، قبلاً از هدر Crypto-Key استفاده می‌کنید، بنابراین برای افزودن کلید سرور برنامه، فقط باید قبل از افزودن محتوای فوق، یک نقطه ویرگول اضافه کنید که نتیجه آن:

dh=BGEw2wsHgLwzerjvnMTkbKrFRxdmwJ5S_k7zi7A1coR_sVjHmGrlvzYpAT1n4NPbioFlQkIrTNL8EH4V3ZZ4vJE;
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaN

واقعیت این تغییرات

با VAPID دیگر نیازی به ثبت نام برای یک حساب کاربری با GCM برای استفاده از فشار در کروم ندارید و می توانید از همان مسیر کد برای اشتراک کاربر و ارسال پیام به کاربر در کروم و فایرفاکس استفاده کنید. هر دو از استانداردها پیروی می کنند.

آنچه باید در نظر داشته باشید این است که در Chrome 51 و قبل از آن، Opera for Android و مرورگر سامسونگ، همچنان باید gcm_sender_id در مانیفست برنامه وب خود تعریف کنید و باید هدر Authorization را به نقطه پایانی FCM اضافه کنید. بازگردانده خواهد شد.

VAPID یک رمپ خارج از این الزامات اختصاصی را فراهم می کند. اگر VAPID را پیاده سازی کنید در همه مرورگرهایی که از فشار وب پشتیبانی می کنند کار می کند. از آنجایی که مرورگرهای بیشتری از VAPID پشتیبانی می کنند، می توانید تصمیم بگیرید که چه زمانی gcm_sender_id را از مانیفست خود حذف کنید.