Angular2 PWA集成Firebase Messaging获取Token失败,报错缺少认证凭证
我之前也碰到过一模一样的情况——用Angular自带的NGSW做PWA,调用firebase.messaging().getToken()就报messaging/token-subscribe-failed Request is missing required authentication credential错误,但用SwPush却能正常拿到订阅并推送。核心问题其实是Firebase Messaging的默认Service Worker和Angular的NGSW冲突了,而且Firebase的Token获取流程依赖它自己的SW逻辑,直接用NGSW的话认证凭证没法正确传递。
下面给你两个可行的解决方案:
方案一:让Firebase Messaging复用Angular的NGSW
既然你的PWA已经依赖NGSW,没必要再让Firebase注册一个独立的Service Worker。我们可以让Firebase使用Angular已经注册好的SW实例,这样就能兼容Token获取流程:
- 先确保你已经初始化了Firebase App,然后获取Angular的Service Worker注册对象
- 把这个注册对象传给Firebase Messaging的
useServiceWorker方法
代码示例(可以放在app.component.ts或者专门的推送服务里):
import { Component, OnInit } from '@angular/core'; import { SwPush } from '@angular/service-worker'; import firebase from 'firebase/app'; import 'firebase/messaging'; // 你的Firebase配置 const firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "YOUR_AUTH_DOMAIN", projectId: "YOUR_PROJECT_ID", storageBucket: "YOUR_STORAGE_BUCKET", messagingSenderId: "YOUR_SENDER_ID", // 这个必须有,从Firebase控制台拿 appId: "YOUR_APP_ID" }; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { constructor(private swPush: SwPush) {} ngOnInit(): void { // 初始化Firebase firebase.initializeApp(firebaseConfig); // 获取Angular已经注册的SW实例 navigator.serviceWorker.getRegistration().then(registration => { if (registration) { // 让Firebase Messaging使用这个SW firebase.messaging().useServiceWorker(registration); // 现在再尝试获取Token firebase.messaging().getToken({ vapidKey: "YOUR_VAPID_PUBLIC_KEY" }) .then(token => console.log("Firebase Token获取成功:", token)) .catch(err => console.error("Token获取失败:", err)); } }); } }
注意:这里的vapidKey需要和你Firebase控制台里配置的一致,或者用Firebase生成的VAPID公钥(在项目设置>云消息传递>Web配置里能找到)。
方案二:继续使用SwPush,结合Firebase存储订阅信息
既然你已经能用SwPush.requestSubscription()拿到订阅,并且通过Web Push库发送成功,完全可以继续用这个方案,同时把订阅信息同步到Firebase(比如Firestore),方便后续从Firebase触发推送:
- 用SwPush获取订阅后,将订阅对象转成JSON存储到Firestore
- 在Firebase Cloud Functions中读取这些订阅,用web-push库发送消息
代码示例(存储订阅):
import { Injectable } from '@angular/core'; import { SwPush } from '@angular/service-worker'; import { AngularFirestore } from '@angular/fire/firestore'; @Injectable({ providedIn: 'root' }) export class PushNotificationService { private readonly VAPID_PUBLIC_KEY = "YOUR_VAPID_PUBLIC_KEY"; constructor(private swPush: SwPush, private firestore: AngularFirestore) {} requestSubscription(): void { this.swPush.requestSubscription({ serverPublicKey: this.VAPID_PUBLIC_KEY }) .then(subscription => { // 将订阅存储到Firestore return this.firestore.collection('pushSubscriptions').add(subscription.toJSON()); }) .then(docRef => console.log("订阅已存储,ID:", docRef.id)) .catch(err => console.error("订阅请求失败:", err)); } }
这个方案的好处是不用改动现有SW逻辑,直接复用Angular的SwPush,适合已经搭建好Web Push推送流程的场景。
为什么原来的getToken会报错?
Firebase Messaging默认会注册自己的Service Worker(firebase-messaging-sw.js),但Angular的NGSW已经是当前激活的SW,两者会冲突。而且Firebase的Token获取流程需要它自己的SW来处理认证凭证的传递,NGSW没有集成这些逻辑,所以就会出现“缺少认证凭证”的错误。
内容的提问来源于stack exchange,提问作者majodi

