如何在Google Cloud Function中使用FCM?权限认证问题待解
解决Google Cloud Function中使用FCM的认证与权限问题
核心问题分析
你遇到的cloudmessaging.messages.create权限拒绝错误,本质是Cloud Function(CF)使用的服务账号缺少FCM消息发送的必要权限;同时CF环境无法直接读取本地JSON密钥文件,需要调整密钥的加载方式。
一、权限配置的正确步骤
- 确定CF使用的服务账号
- 默认情况下,CF使用的服务账号格式为:
[你的CF项目ID]@appspot.gserviceaccount.com;如果自定义了服务账号,以CF配置页显示的为准。
- 默认情况下,CF使用的服务账号格式为:
- 给服务账号添加FCM权限
- 进入Firebase关联的GCP项目IAM页面,添加上述服务账号为成员,赋予Firebase Cloud Messaging Admin角色(
roles/firebase.messagingAdmin)。这个角色包含cloudmessaging.messages.create权限,能直接解决权限拒绝问题。 - 注意:如果CF和Firebase分属不同GCP项目,必须在Firebase所在项目的IAM中添加CF的服务账号,而非CF项目的IAM。
- 进入Firebase关联的GCP项目IAM页面,添加上述服务账号为成员,赋予Firebase Cloud Messaging Admin角色(
二、密钥文件的处理与代码适配
CF环境不支持读取本地文件(如WEB-INF下的JSON密钥),推荐两种方案:
方案1:使用CF默认服务账号(推荐,无需密钥文件)
GCP会自动为CF注入默认服务账号的凭证,无需手动加载JSON密钥,代码可简化为:
import com.google.auth.oauth2.GoogleCredentials; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.messaging.FirebaseMessaging; // 初始化Firebase(仅需执行一次) if (FirebaseApp.getApps().isEmpty()) { FirebaseOptions options = new FirebaseOptions.Builder() .setCredentials(GoogleCredentials.getApplicationDefault()) .setDatabaseUrl("https://my-firebase-project.firebaseio.com") // 无需数据库可移除 .build(); FirebaseApp.initializeApp(options); } // 发送FCM消息示例 FirebaseMessaging messaging = FirebaseMessaging.getInstance(); // 构造并发送消息(此处省略消息构造逻辑)
方案2:通过Secret Manager管理密钥文件(若必须使用自定义密钥)
- 存储密钥到Secret Manager
- 在GCP控制台的Secret Manager中创建新Secret,将Firebase JSON密钥的内容粘贴进去。
- 给CF的服务账号添加Secret Manager Secret Accessor角色(
roles/secretmanager.secretAccessor),允许其读取该Secret。
- 代码中读取密钥并初始化
import com.google.cloud.secretmanager.v1.AccessSecretVersionResponse; import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; import com.google.cloud.secretmanager.v1.SecretVersionName; import com.google.auth.oauth2.GoogleCredentials; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import java.io.ByteArrayInputStream; // 读取Secret Manager中的密钥内容 String secretId = "你的Secret名称"; String projectId = "你的CF项目ID"; try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { SecretVersionName versionName = SecretVersionName.of(projectId, secretId, "latest"); AccessSecretVersionResponse response = client.accessSecretVersion(versionName); String secretContent = response.getPayload().getData().toStringUtf8(); // 初始化Firebase if (FirebaseApp.getApps().isEmpty()) { FirebaseOptions options = new FirebaseOptions.Builder() .setCredentials(GoogleCredentials.fromStream( new ByteArrayInputStream(secretContent.getBytes()) )) .setDatabaseUrl("https://my-firebase-project.firebaseio.com") .build(); FirebaseApp.initializeApp(options); } } catch (Exception e) { // 处理异常 }
三、额外检查项
- 确保Firebase项目的Firebase Cloud Messaging API已在GCP API库中启用。
- 验证错误日志中的项目ID与代码中
setDatabaseUrl或FCM调用使用的项目ID完全一致。 - 若为跨项目调用,确认Firebase项目的IAM中已正确添加CF服务账号,且角色生效(权限变更可能需要数分钟同步)。
内容的提问来源于stack exchange,提问作者Mike Dee
相关产品推荐
相关产品推荐

