Google PHP Api 客户端 - 我一直收到错误 401:未经授权

Google PHP Api Client - I keep getting Error 401: UNAUTHENTICATED

我已经为此苦苦挣扎了几个小时,如果不是几天的话,我似乎无法解决它。

我对 Cloud Functions 的请求被拒绝,错误代码:401:未经授权。

我的代码如下:

    putenv('GOOGLE_APPLICATION_CREDENTIALS=' . FIREBASE_SERIVCE_PATH);

    $client = new Google_Client();
    $client->useApplicationDefaultCredentials();
    $client->addScope(Google_Service_CloudFunctions::CLOUD_PLATFORM);
    $httpClient = $client->authorize();


    $promise = $httpClient->requestAsync("POST", "<MyCloudFunctionExecutionUri>", ['json' => ['data' => []]]);
    $promise->then(
        function (ResponseInterface $res) {
            echo "<pre>";
            print_r($res->getStatusCode());
            echo "</pre>";

        },
        function (RequestException $e) {
            echo $e->getMessage() . "\n";
            echo $e->getRequest()->getMethod();
        }
    );
    $promise->wait();

我目前正在从本地主机执行此操作,因为我仍处于开发阶段。

我的 FIREBASE_SERIVCE_PATH 经常链接到我的 service_account js

我的云函数index.js:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();


// CORS Express middleware to enable CORS Requests.
const cors = require('cors')({
  origin: true,
});

exports.testFunction = functions.https.onCall((data, context) => {
    return new Promise((resolve, reject) => {
        resolve("Ok:)");
    });
  });
  // [END all]

我的云函数日志: Function execution took 459 ms, finished with status code: 401

我做错了什么导致我未通过身份验证?

PS:当我的 Flutter 移动应用程序调用我的 testFunction 时,我的 testFunction 完美运行:https://pub.dartlang.org/packages/cloud_functions

更新:

我遵循了这个指南:https://developers.google.com/api-client-library/php/auth/service-accounts 但在 "Delegating domain-wide authority to the service account" 部分,它只说明如果我的应用程序在 Google 应用程序域中运行,但是我不会使用 Google Apps 域,而且我在本地主机上。

可调用函数在常规 HTTP 函数之上强加 protocol。通常您使用 Firebase 客户端 SDK 调用它们。由于您没有可用于实现该协议的 SDK,因此您必须自己遵循它。您不能像普通的 HTTP 函数那样调用它们。

如果您不想实施 protocol,您应该改用常规 HTTP 函数,并停止在您的移动应用中使用客户端 SDK。

首先感谢Doug Stevenson 的回答!它帮助我获得了可调用函数的有效解决方案 (functions.https.onCall)。 主要思想是此类函数需要已登录的 Firebase 用户的身份验证上下文。它不是服务帐户,它是 Firebase 项目的身份验证部分中的用户记录。因此,首先,我们必须授权用户,从响应中获取 ID 令牌,然后将此令牌用于调用可调用函数的请求。 所以,下面是我的工作片段(实际上来自 Drupal 8 项目)。

use Exception;
use Google_Client;
use Google_Service_CloudFunctions;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Promise;
use GuzzleHttp\RequestOptions;

$client = new Google_Client();
$config_path = <PATH TO SERVICE ACCOUNT JSON FILE>;
$json = file_get_contents($config_path);
$config = json_decode($json, TRUE);
$project_id = $config['project_id'];
$options = [RequestOptions::SYNCHRONOUS => TRUE];
$client->setAuthConfig($config_path);
$client->addScope(Google_Service_CloudFunctions::CLOUD_PLATFORM);
$httpClient = $client->authorize();
$handler = $httpClient->getConfig('handler');

/** @var \Psr\Http\Message\ResponseInterface $res */
$res = $httpClient->request('POST', "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=<YOUR FIREBASE PROJECT API KEY>", [
  'json' => [
    'email' => <FIREBASE USER EMAIL>,
    'password' => <FIREBASE USER PASSWORD>,
    'returnSecureToken' => TRUE,
  ],
]);
$json = $res->getBody()->getContents();
$data = json_decode($json);
$id_token = $data->idToken;

$request = new Request('POST', "https://us-central1-$project_id.cloudfunctions.net/<YOUR CLOUD FUNCTION NAME>", [
  'Content-Type' => 'application/json',
  'Authorization' => "Bearer $id_token",
], Psr7\stream_for(json_encode([
  'data' => [],
])));

try {
  $promise = Promise\promise_for($handler($request, $options));
}
catch (Exception $e) {
  $promise = Promise\rejection_for($e);
}

try {
  /** @var \Psr\Http\Message\ResponseInterface $res */
  $res = $promise->wait();
  $json = $res->getBody()->getContents();
  $data = json_decode($json);
  ...
}
catch (Exception $e) {
}