douhao2153 2017-01-06 13:52
浏览 72
已采纳

带有服务帐户的Google云端存储 - 403禁止访问

I'm implementing a cron fetching automatically my application installation stats on Google Play Store. So, I need to download a file from Google Cloud Storage and parse it. I made this code :

// Set scopes to authorize full control of Cloud Storage

$scopes = array("https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/devstorage.full_control");


// Create new Google Client

$client = new Google_Client();


// Set path to ServiceAccount's credentials and link them to Google Client

putenv('GOOGLE_APPLICATION_CREDENTIALS=../../libs/GoogleAPICredentials/client_credentials_CPTS.json');
$client->useApplicationDefaultCredentials();
$client->setScopes($scopes);


// Create new Google Service Storage object to handle our repository

$service = new Google_Service_Storage($client);


// Get content of GCS repository

$request = $service->objects->listObjects("MY_BUCKET");


// Settings folders, files, buckets, names

$sourceBucket = "pubsite_prod_rev_BUCKET_IDENTIFIER";
$sourceObject = "installs_MY_APP_IDENTIFIER_" . $date->format("Ym") . "_overview.csv";
$localFile = "../files/temp/installs_MY_APP_IDENTIFIER_" . $date->format("Ym") . "_overview.csv";
$fullSrcObj = "stats/installs/" . $sourceObject;
$destinationBucket = "MY_BUCKET";
$destinationObject = $sourceObject;


// Create new Google Service Storage StorageObject object to handle a single object (file)

$postBody = new Google_Service_Storage_StorageObject($client);


try {
    // Copy stats app .CSV file from orignal repository (Google Play Store) to our bucket

    $response = $service->objects->copy($sourceBucket, $fullSrcObj, $destinationBucket, $destinationObject, $postBody);


    // Get the new object

    try {
        $object = $service->objects->get($destinationBucket, $destinationObject);
    }
    catch (Google_Service_Exception $e) {
        if ($e->getCode() == 404)
            echo ("[<b><span style=\"color:#DA4F34\">ERROR</span></b>] <b><span style=\"color:#DA4F34\">". $e->getMessage() ."</span></b><br><br>");
        throw $e;
    }


    // Download the new object on the MY_COMPAGNY server

    $uri = sprintf('https://storage.googleapis.com/%s/%s?alt=media&generation=%s', $destinationBucket, $destinationObject, $object->generation);
    $http = $client->authorize();
    $response = $http->get($uri);

    if ($response->getStatusCode() != 200) {
        echo ("[<b><span style=\"color:#DA4F34\">ERROR</span></b>] <b><span style=\"color:#DA4F34\">An unhandled error append !</span></b><br><br>");
        die();
    }


    // Save it into local file on MY_COMPAGNY server

    file_put_contents($localFile, $response->getBody());


    // Convert .CSV into php array

    $csv = array_map('str_getcsv', file($localFile));


    // Delete local file

    unlink($localFile);


    // Remove last line of CSV (Array) --> Empty - And remove first line of CSV (Array) --> Title line

    array_shift($csv);
    array_pop($csv);


    // Insert each line into MY_COMPAGNY Database

    $success = false;
    foreach ($csv as $row) {
        $success = insertAppInstallData(filter_var($row[0], FILTER_SANITIZE_STRING), (int)filter_var($row[$columnTotal], FILTER_SANITIZE_NUMBER_INT), (int)filter_var($row[$columnCurrent], FILTER_SANITIZE_NUMBER_INT))?true:  $success;
    }
    if (!$success)
        echo ("[<b><span style=\"color:#DA4F34\">ERROR</span></b>] <b><span style=\"color:#DA4F34\">DataBase insertion failure</span></b><br><br>");

}
catch (Google_Service_Exception $E) {
    echo ("[<b><span style=\"color:#DA4F34\">ERROR</span></b>] <b><span style=\"color:#DA4F34\">".$E->getMessage()." - ".$E->getTraceAsString()."</span></b><br><br>");
}

With an user account, it's work well but with a Service account, I have a 403 error, Forbidden on the call to $service->objects->copy().

{ 
   "error": 
   { 
        "errors": [ 
        { 
            "domain": "global", 
            "reason": "forbidden", 
            "message": "Forbidden" 
        }], 
        "code": 403, 
        "message": "Forbidden" 
    } 
}

I checks twice if there are good credentials, IAM authorizations, OAuth client, ... and it still dosent work.

I'm not on a Google Engine, I running on a personal Engine.

Someone have an idea ?

Have a good day and Happy New Year !

Ben.

  • 写回答

1条回答 默认 最新

  • dongmi19720408 2017-01-06 16:43
    关注

    The reason you are getting error 403 is because you are missing the domain wide delegation and the user impersonation step. Please refer to the documentation here to understand how you can access user data with service accounts.

    The process is like this:

    $scopes = array("https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/devstorage.full_control");
    
    $client = new Google_Client();
    $client->useApplicationDefaultCredentials();    
    $client->addScope($scopes); //Set scopes to client object
    $client->setSubject("user@domain.com"); // replace with the user account
    

    You are able to make it work with a user account because the user already has access to the resource but not the service account, hence the error 403 forbidden. Unfortunately, the domain wide delegation process and user impersonation only works with G Suite accounts( formerly Google Apps ). Another alternative would be to share the resources with the service account but that is something that I haven´t explored yet and not sure if it is possible. You can also refer to the PHP Client Lib documentation here. I hope this information is helpful.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥200 uniapp长期运行卡死问题解决
  • ¥15 latex怎么处理论文引理引用参考文献
  • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?