【问题标题】:Google PHP Api Client - I keep getting Error 401: UNAUTHENTICATEDGoogle PHP Api 客户端 - 我不断收到错误 401:未验证
【发布时间】:2019-07-16 00:26:55
【问题描述】:

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

我对 Cloud Functions 的请求被拒绝,错误代码为:401: UNAUTHENTICATED。

我的代码如下:

    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();

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

我的 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,但在“将域范围内的权限委派给服务帐户”部分中,它仅说明如果我的应用程序在 Google Apps 域中运行,但我不会使用 Google Apps 域,并且另外我在本地主机上。

【问题讨论】:

    标签: php google-api google-cloud-functions google-api-php-client


    【解决方案1】:

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

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

    【讨论】:

    • 我需要从我的 PHP 客户端而不是移动应用程序调用该函数。这是一个服务器到服务器调用。
    • 你的意思是我应该使用 functions.https.onRequest 代替?
    • 当我使用 functions.https.onRequest 而不是可调用函数时,它起作用了!非常感谢你的帮助,我开始失去理智了xD
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2021-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-11
      • 2016-03-15
      • 2021-01-07
      相关资源
      最近更新 更多