从您的应用服务器或受信任环境发送到 FCM 的请求必须经过授权。请注意弃用的旧版 HTTP API 与 HTTP v1 API 授权之间存在以下重大差异:
- FCM HTTP v1 API 使用短期有效的 OAuth 2.0 访问令牌为请求提供授权。如需创建此令牌,您可以使用 Google 应用默认凭据(在 Google 服务器环境中)以及/或者手动从为服务账号生成的 JSON 私钥文件中获取所需的凭据。 如果您使用 Firebase Admin SDK 发送消息,该库会为您处理令牌。
- 已弃用的旧版协议只能使用从 Firebase 控制台获取的长期有效的 API 密钥。
为 HTTP v1 发送请求 (send request) 提供授权
根据服务器环境的详细信息,您可以组合使用以下策略为服务器向 Firebase 服务发送的请求提供授权:
- Google 应用默认凭据 (ADC)
- 服务账号 JSON 文件
- 源自服务账号的短期有效的 OAuth 2.0 访问令牌
如果您的应用在 Compute Engine、Google Kubernetes Engine、App Engine 或 Cloud Functions(包括 Cloud Functions for Firebase)上运行,请使用应用默认凭据 (ADC)。ADC 会使用您现有的默认服务账号来获取用于为请求提供授权的凭据,并可通过环境变量 GOOGLE_APPLICATION_CREDENTIALS 实现灵活的本地测试。为了最大限度地自动化授权流程,请将 ADC 与 Admin SDK 服务器库搭配使用。
如果您的应用在非 Google 服务器环境中运行,则需要从 Firebase 项目下载服务账号 JSON 文件。只要您有权访问包含私钥文件的文件系统,就可以通过环境变量 GOOGLE_APPLICATION_CREDENTIALS 利用这些手动获取的凭据为请求提供授权。如果您没有此类文件访问权限,则必须在代码中引用服务账号文件,但这样做存在凭据泄露的风险,因此请务必谨慎。
使用 ADC 提供凭据
Google 应用默认凭据 (ADC) 按以下顺序查找您的凭据:
ADC 检查是否已设置环境变量 GOOGLE_APPLICATION_CREDENTIALS。如果设置了该变量,ADC 就会使用该变量指向的服务账号文件。
如果未设置环境变量,则对于在 Compute Engine、Google Kubernetes Engine、App Engine 和 Cloud Functions 上运行的应用,ADC 会使用这些服务提供的默认服务账号。
如果 ADC 无法使用上述任何凭据,系统会抛出一个错误。
以下 Admin SDK 代码示例展示了该策略。该示例并未明确指定应用凭据。但是,只要设置了该环境变量,或者只要应用在 Compute Engine、Google Kubernetes Engine、App Engine 或 Cloud Functions 上运行,ADC 便能够隐式查找凭据。
Node.js
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
Java
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
Python
default_app = firebase_admin.initialize_app()
Go
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
C#
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
});
手动提供凭据
Firebase 项目支持 Google 服务账号,您可以使用这些账号从应用服务器或受信任环境调用 Firebase 服务器 API。如果您是在本地编写代码,或是在本地部署您的应用,则可以使用通过此服务账号获取的凭据来对服务器请求进行授权。
如需对服务账号进行身份验证并授予其访问 Firebase 服务的权限,您必须生成 JSON 格式的私钥文件。
如需为您的服务账号生成私钥文件,请执行以下操作:
在 Firebase 控制台中,依次打开设置 > 服务账号。
点击生成新的私钥,然后点击生成密钥进行确认。
妥善存储包含密钥的 JSON 文件。
通过服务账号进行授权时,有两种方式可为您的应用提供凭据。您可以设置 GOOGLE_APPLICATION_CREDENTIALS 环境变量,也可以在代码中明确传递服务账号密钥的路径。第一种方式更为安全,因此强烈推荐使用此方式。
如需设置该环境变量,请执行以下操作:
将环境变量 GOOGLE_APPLICATION_CREDENTIALS 设置为包含服务账号密钥的 JSON 文件的路径:此变量仅适用于当前的 Shell 会话,因此请在开始新的会话时重新设置该变量。
Linux 或 macOS
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"
Windows
使用 PowerShell:
$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"
完成上述步骤后,应用默认凭据 (ADC) 便能隐式确定您的凭据,这样,在非 Google 环境中测试或运行应用时,您就能使用服务账号凭据。
使用凭据来创建访问令牌
除非您使用自动处理授权的 Admin SDK,否则均需创建访问令牌并将其添加到发送请求中。
将您的 Firebase 凭据与适用于您的偏好语言的 Google Auth 库结合使用,以检索短期有效的 OAuth 2.0 访问令牌:
node.js
function getAccessToken() {
return new Promise(function(resolve, reject) {
const key = require('../placeholders/service-account.json');
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
SCOPES,
null
);
jwtClient.authorize(function(err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
在此示例中,Google API 客户端库使用 JSON Web 令牌 (JWT) 对请求进行身份验证。有关详情,请参阅 JSON Web 令牌。
Python
def _get_access_token():
"""Retrieve a valid access token that can be used to authorize requests.
:return: Access token.
"""
credentials = service_account.Credentials.from_service_account_file(
'service-account.json', scopes=SCOPES)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
return credentials.token
Java
private static String getAccessToken() throws IOException {
GoogleCredentials googleCredentials = GoogleCredentials
.fromStream(new FileInputStream("service-account.json"))
.createScoped(Arrays.asList(SCOPES));
googleCredentials.refresh();
return googleCredentials.getAccessToken().getTokenValue();
}
在您的访问令牌到期后,系统会自动调用令牌刷新方法以检索更新的访问令牌。
如需授予访问 FCM 的权限,则需请求 https://www.googleapis.com/auth/firebase.messaging
范围。
如需将访问令牌添加到 HTTP 请求标头中,请使用以下代码:
以 Authorization: Bearer <access_token>
格式将令牌添加为 Authorization
标头的值:
node.js
headers: {
'Authorization': 'Bearer ' + accessToken
}
Python
headers = {
'Authorization': 'Bearer ' + _get_access_token(),
'Content-Type': 'application/json; UTF-8',
}
Java
URL url = new URL(BASE_URL + FCM_SEND_ENDPOINT);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Bearer " + getServiceAccountAccessToken());
httpURLConnection.setRequestProperty("Content-Type", "application/json; UTF-8");
return httpURLConnection;
为旧版协议发送请求提供授权
使用 HTTP 旧版协议时,每个请求都必须包含来自 Firebase 控制台设置窗格的 Cloud Messaging 标签页的服务器密钥。对于 XMPP,您必须使用该服务器密钥来建立连接。
迁移旧服务器密钥
从 2020 年 3 月开始,FCM 已停止创建旧服务器密钥。现有的旧服务器密钥仍然有效,但我们建议您改用 Firebase 控制台中标记为服务器密钥的新版密钥。
如果要删除现有的旧服务器密钥,您可以在 Google Cloud 控制台中执行此操作。
为 HTTP 请求提供授权
消息请求由两部分组成:HTTP 标头和 HTTP 正文。 HTTP 标头必须包含以下标头:
Authorization
: key=YOUR_SERVER_KEY
请确保这是服务器密钥,您可以在 Firebase 控制台设置窗格的 Cloud Messaging 标签页找到该密钥的值。Android、Apple 平台和浏览器密钥会被 FCM 拒绝。Content-Type
:application/json
(JSON 格式);application/x-www-form-urlencoded;charset=UTF-8
(纯文本格式)。
如果省略Content-Type
,则视为纯文本格式。
例如:
Content-Type:application/json Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA { "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...", "data" : { ... }, }
如需详细了解如何创建发送请求,请参阅构建发送请求。旧版 HTTP 协议参考文档提供了您的消息可以包含的所有参数的列表。
检查服务器密钥的有效性
如果您在发送消息时收到身份验证错误,请检查服务器密钥的有效性。例如,在 Linux 上运行以下命令:
api_key=YOUR_SERVER_KEY curl --header "Authorization: key=$api_key" \ --header Content-Type:"application/json" \ https://fcm.googleapis.com/fcm/send \ -d "{\"registration_ids\":[\"ABC\"]}"
如果您收到 401 HTTP 状态代码,则表示您的服务器密钥无效。
为 XMPP 连接提供授权
使用 XMPP,您可以保持与 FCM 服务器之间的持久异步双向连接。该连接可用于在您的服务器与已连接到 FCM 的用户设备之间发送和接收消息。
您可以使用大多数 XMPP 库来管理与 FCM 之间的长期连接。XMPP 端点在 fcm-xmpp.googleapis.com:5235
上运行。针对非生产环境下的用户进行功能测试时,应改为连接到位于 fcm-xmpp.googleapis.com:5236
的测试用服务器(注意端口的不同)。
在测试环境(一个运行最新 FCM 版本的较小的环境)中进行常规测试有助于将真实用户与测试代码隔离。连接到 fcm-xmpp.googleapis.com:5236
的测试设备和测试代码应使用不同的 FCM 发送者 ID,以避免向正式使用环境中的用户发送测试消息,或通过测试连接发送来自正式使用环境流量的上行消息。
连接需要符合两个重要条件:
- 您必须启动传输层安全协议 (TLS) 连接。请注意,FCM 目前不支持 STARTTLS 扩展程序。
- FCM 需要一种使用
<your_FCM_Sender_Id>@fcm.googleapis.com
(FCM 发送者 ID)并以服务器密钥作为密码的 SASL PLAIN 身份验证机制。您可以在 Firebase 控制台设置窗格的 Cloud Messaging 标签页找到这些值。
无论什么时候连接失败,您都应立即重新连接。如果身份验证后连接断开,无需退避。FCM 允许每个发送者 ID 有 2500 个并行连接。
以下这段代码说明了如何为与 FCM 的 XMPP 连接进行身份验证以及提供授权。
XMPP 服务器
XMPP 服务器请求连接到 FCM
<stream:stream to="fcm.googleapis.com" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
FCM
FCM 打开连接并请求身份验证机制,包括 PLAIN
方法。
<stream:features> <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> <mechanism>X-OAUTH2</mechanism> <mechanism>X-GOOGLE-TOKEN</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features>
XMPP 服务器
XMPP 服务器必须使用 PLAIN
身份验证方法进行响应,并提供来自 Firebase 控制台设置窗格的 Cloud Messaging 标签页的服务器密钥。
<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">MTI2MjAwMzQ3OTMzQHByb2plY3RzLmdjbS5hb mFTeUIzcmNaTmtmbnFLZEZiOW1oekNCaVlwT1JEQTJKV1d0dw==</auth>
FCM
<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
XMPP 服务器
<stream:stream to="fcm.googleapis.com" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
FCM
<stream:features> <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/> <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/> </stream:features>
XMPP 服务器
<iq type="set"> <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"></bind> </iq>
FCM
<iq type="result"> <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"> <jid>SENDER_ID@fcm.googleapis.com/RESOURCE</jid> </bind> </iq>
注意:FCM 在传递消息时不使用绑定的资源。
如需详细了解如何创建发送请求,请参阅构建发送请求。旧版 XMPP 协议参考提供了您的消息可以包含的所有参数的列表。