从您的应用服务器或受信任环境发送到 FCM 的请求必须经过授权。
为 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 便能够隐式查找凭据。
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
default_app = firebase_admin.initialize_app()
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
});
手动提供凭据
Firebase 项目支持 Google 服务账号,您可以使用这些账号从应用服务器或受信任环境调用 Firebase 服务器 API。如果您是在本地编写代码,或是在本地部署您的应用,则可以使用通过此服务账号获取的凭据来对服务器请求进行授权。
如需对服务账号进行身份验证并授予其访问 Firebase 服务的权限,您必须生成 JSON 格式的私钥文件。
如需为您的服务账号生成私钥文件,请执行以下操作:
在 Firebase 控制台中,依次打开设置 > 服务账号。
点击生成新的私钥,然后点击生成密钥进行确认。
妥善存储包含密钥的 JSON 文件。
通过服务账号进行授权时,有两种方式可为您的应用提供凭据。您可以设置 GOOGLE_APPLICATION_CREDENTIALS 环境变量,也可以在代码中明确传递服务账号密钥的路径。第一种方式更为安全,因此强烈推荐使用此方式。
如需设置该环境变量,请执行以下操作:
将环境变量 GOOGLE_APPLICATION_CREDENTIALS 设置为包含服务账号密钥的 JSON 文件的路径:此变量仅适用于当前的 Shell 会话,因此请在开始新的会话时重新设置该变量。
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"
使用 PowerShell:
$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"
完成上述步骤后,应用默认凭据 (ADC) 便能隐式确定您的凭据,这样,在非 Google 环境中测试或运行应用时,您就能使用服务账号凭据。
使用凭据来创建访问令牌
除非您使用自动处理授权的 Admin SDK,否则均需创建访问令牌并将其添加到发送请求中。
将您的 Firebase 凭据与适用于您的偏好语言的 Google Auth 库结合使用,以检索短期有效的 OAuth 2.0 访问令牌:
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 令牌。
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
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
标头的值:
headers: {
'Authorization': 'Bearer ' + accessToken
}
headers = {
'Authorization': 'Bearer ' + _get_access_token(),
'Content-Type': 'application/json; UTF-8',
}
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;