如何获取Google服务账号永久访问令牌?iOS设备间推送优化方案
iOS设备间FCM推送的令牌过期问题与最优实现方案
问题背景
开发基于Swift的iOS应用,通过FCM实现设备间推送通知,当前手动运行Python脚本获取服务账号访问令牌,复制到Swift代码中调用FCM API实现推送。但令牌每1小时过期,需手动重新生成复制,且无自建服务器自动执行脚本,需解决令牌管理问题或找到符合规范的设备间推送方式。
当前Swift发送通知代码:
let accessToken = "xxxx" let urlString = "https://fcm.googleapis.com/v1/projects/\( K.FCMessaging.projectId)/messages:send" let url = NSURL(string: urlString)! let paramString: [String : Any] = ["message": [ "apns" : ["payload" : ["aps": ["alert": ["title": title, "body": body], "sound": "default"] as [String : Any], OrderModel.CodingKeys.orderId.rawValue: order.orderId!, OrderModel.CodingKeys.senderId.rawValue: order.senderId] as [String : Any]], "token" : receiverToken] as [String : Any] ] let request = NSMutableURLRequest(url: url as URL) request.httpMethod = "POST" request.httpBody = try? JSONSerialization.data(withJSONObject:paramString) request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") let task = URLSession.shared.dataTask(with: request as URLRequest) task.resume()
获取令牌的Python代码:
import argparse import json import requests import google.auth.transport.requests from google.oauth2 import service_account PROJECT_ID = 'xxxx' BASE_URL = 'https://fcm.googleapis.com' FCM_ENDPOINT = 'v1/projects/' + PROJECT_ID + '/messages:send' FCM_URL = BASE_URL + '/' + FCM_ENDPOINT SCOPES = ['https://www.googleapis.com/auth/firebase.messaging'] def access_token(): credentials = service_account.Credentials.from_service_account_file('/Users/...-firebase-xxxx.json', scopes=SCOPES) request = google.auth.transport.requests.Request() credentials.refresh(request) return credentials.token
核心结论与解决方案
1. 不存在永久有效的FCM访问令牌
Google OAuth2机制下,服务账号生成的访问令牌默认1小时过期,这是强制的安全设计,无法绕过或生成永久令牌。
2. 最优实现:使用Firebase Cloud Functions自动处理推送
这是无需自建服务器、安全省心的标准方案,完全规避令牌管理问题:
- 原理:在Firebase控制台创建无服务器函数,监听Firestore/Realtime Database的事件(比如新消息文档创建),自动调用FCM发送推送,Cloud Functions会自动处理服务账号令牌的刷新与管理
- 示例Node.js代码:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.sendNotification = functions.firestore.document('messages/{messageId}') .onCreate(async (snap, context) => { const messageData = snap.data(); const receiverToken = messageData.receiverToken; const payload = { apns: { payload: { aps: { alert: { title: messageData.title, body: messageData.body }, sound: "default" }, orderId: messageData.orderId, senderId: messageData.senderId } }, token: receiverToken }; try { await admin.messaging().send(payload); functions.logger.info("Notification sent successfully"); } catch (error) { functions.logger.error("Error sending notification:", error); } }); - iOS端只需将消息数据(标题、内容、接收方令牌、订单ID等)写入Firestore/Realtime Database,Cloud Functions会自动触发推送流程
3. 禁止在客户端直接集成Admin SDK
Firebase Admin SDK包含敏感的服务账号密钥,绝对不能嵌入iOS客户端代码,否则会导致密钥泄露,任何人都可滥用你的FCM服务发送推送,带来安全风险和资源损失。
4. 不推荐的客户端令牌刷新方案
如果暂时无法使用Cloud Functions,理论上可在iOS端集成Google OAuth2库自动刷新令牌,但这种方式需要嵌入服务账号密钥,存在极高安全风险,可能导致你的FCM资源被恶意滥用,强烈不建议采用。
总结
使用Firebase Cloud Functions是当前场景下最安全、最符合FCM设计规范的方案,完全无需手动管理令牌,也不需要自建服务器,能稳定实现设备间的推送需求。
内容的提问来源于stack exchange,提问作者BB119
相关产品推荐
相关产品推荐

