使用 VAPID 进行 Web 推送:400/401 未经授权的注册

2024-01-10

首先,我已经检查过这些问题,但没有任何运气:

  • Web Push API Chrome,返回“未经授权的注册” https://stackoverflow.com/questions/40801235/web-push-api-chrome-returning-unauthorized-registration
  • [WebPush][VAPID] 请求失败,出现 400 UnauthorizedRegistration https://stackoverflow.com/questions/39336523/webpushvapid-request-fails-with-400-unauthorizedregistration

我正在尝试为我正在开发的网络应用程序实现网络推送通知。目前,我已经实现了以下目标:

  • 创建 VAPID 密钥对(有了本指南 https://github.com/MartijnDwars/web-push/blob/master/doc/VAPID.md#generate-a-keypair).
  • 注册一个 Service Worker (只有一个 Service Worker,我认为manifest.json不再需要)。
  • 将用户订阅到服务器(订阅数据将存储在数据库中)。
  • 发送推送通知webpush https://github.com/zaru/webpush gem.

设置完成后,一切正常(在本地主机和远程计算机上)。然而,几个小时后(12 到 24 小时之间),通知在远程计算机上停止工作(本地主机工作完美)。在此之后,从服务器端 (Rails) 发送推送通知时会引发以下错误:

  • Chrome: UnauthorizedRegistration 400(没有额外信息)。
  • Firefox: {"code": 401, "errno": 109, "error": "Unauthorized", "more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes", "message": "Request did not validate Invalid bearer token: Auth > 24 hours in the future"}

出现此错误后,我尝试在每次访问页面时取消订阅并重新订阅用户。重新订阅完成后,数据库上的订阅字段已更新,但仍然抛出错误,并具有相同的信息。浏览器和服务工作线程上都不会抛出任何错误。

I've tried to force the resubscription manually by placing some js code on the Chrome Dev Tools console, unregistering the service worker, and reseting the push notification permissions, but nothing solves the error. I can only fix this error by creating a new VAPID key pair rebooting the remote machine. After crebooting the machine, I've another 12-24 hours before it fails again. Also, the notifications send process don't work neither on rails server (nginx + unicorn), rails console, nor irb.

我不知道从现在起该去哪里。更糟糕的是,我每天只能尝试修复一次,因为它每 24 小时就会崩溃一次。我想我需要一些外部帮助来对问题有一个新的认识。我错过了什么吗? VAPID 使用并需要重新启动是否存在任何操作系统依赖性?


以下是一些可能有用的代码片段。很抱歉造成混乱,但我已经做了大量修改以尝试使其正常工作。

服务人员注册:

serviceWorkerRegistration = null

registerServiceWorker = ->
  if 'serviceWorker' of navigator && 'PushManager' of window
    navigator.serviceWorker.register("<js url>").then (reg) ->
      serviceWorkerRegistration = reg
      checkSubscription()

    .catch (error) ->
      console.warn 'Service Worker Error', error

  else
    console.warn 'Push messaging is not supported'

registerServiceWorker()

用户订阅和重新订阅

# Refresh user subscription (unsub + sub)
refreshUserSubscription = ->
  unsubscribeUser(subscribeUser)

# Subscribe the user to the push server
subscribeUser = ->
  return if !serviceWorkerRegistration

  # Subscribe
  serviceWorkerRegistration.pushManager.subscribe
    userVisibleOnly: true
    applicationServerKey: urlB64ToUint8Array('...')

  .then (subscription) ->
    pushSubscription subscription

  .catch (err) ->
    console.warn 'Failed to subscribe the user: ', err

# Unsubscribe user
unsubscribeUser = (callback)->
  return unless serviceWorkerRegistration

  serviceWorkerRegistration.pushManager.getSubscription().then (subscription) ->
    if subscription
      subscription.unsubscribe().then(callback)
    else
      callback()
  .catch (error) ->
    console.warn 'Error unsubscribing', error

# Push subscription to the web app
pushSubscription = (subscription) ->
  data = if subscription then subscription.toJSON() else {}
  $.post "<back-end endpoint>", subscription: data

# Fetch current subscription, and push it.
checkSubscription = () ->
  serviceWorkerRegistration.pushManager.getSubscription()
    .then (subscription) ->
      pushSubscription(subscription)

# I think that this should be done with promises instead of a simple timeout.
setTimeout refreshUserSubscription, 1000

服务人员:

self.addEventListener 'push', (event) ->
  title = "Example"
  options = { body: "Example" }

  notificationPromise = self.registration.showNotification(title, options)
  event.waitUntil(notificationPromise)

网页推送调用:

webpush = WebPush.new({ endpoint: '...', keys: { p256dh: '...', auth: '...' } })
webpush.set_vapid_details(
  "mailto:#{CONTACT_EMAIL}",
  "<base64 public key>",
  "<base64 private key>"
)
webpush.send_notification("foo")

将过期时间从 24 小时(默认)更改为 12 小时后,现在可以正常工作了:

Webpush.payload_send(
  message: "Hi!",
  endpoint: "...",
  p256dh: "...",
  auth: "...",
  vapid: {
    subject: "...",
    public_key: ENV['VAPID_PUBLIC_KEY'],
    private_key: ENV['VAPID_PRIVATE_KEY'],
    exp: 12.hours
  }
)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 VAPID 进行 Web 推送:400/401 未经授权的注册 的相关文章

随机推荐