谷歌驱动服务帐户和“请求中的未经授权的客户端或范围"

2022-01-10 00:00:00 google-drive-api php

我有 3 个使用驱动 sdk 的服务帐户.

I have 3 service accounts that are using the drive sdk.

1 有效,2 无效.

返回的错误是Error refresh the OAuth2 token, message: '{ "error" : "unauthorized_client", "error_description" : "Unauthorized client or scope in request." }'"

The error that comes back is "Error refreshing the OAuth2 token, message: '{ "error" : "unauthorized_client", "error_description" : "Unauthorized client or scope in request." }'"

所有 3 个帐户均已在开发者控制台中注册.所有这 3 个都被授权在 Google Apps 控制台中进行托管客户端 API 访问".所有 3 都具有范围https://www.googleapis.com/auth/drive.readonly".驱动器中的所有 3 个,都有一个特定的文件夹供仅查看"共享.

All 3 accounts are registered in the developer console. All 3 are authorised for "Managed Client API access" within Google Apps Console. All 3 have the scope "https://www.googleapis.com/auth/drive.readonly". All 3 in drive, has a specific folder for it shared for "view only".

我正在使用 PHP,我向页面传递了一个参数,该参数称为类型",它反映了帐户的用途,1 用于公共,1 用于会员,1 用于管理员.

I am using PHP and I pass one parameter to the page which is called "type" and reflects what the purpose of the account is for, 1 for public, 1 for member and 1 for admin.

例如

http://www.somehost.com/oauth_client.php?type=googledrive_admin

p12 证书和用户值存储在服务器上.所有ini"文件都具有相同的值结构、client_id、client_email、范围和查询过滤器.在所有情况下,文件之间唯一更改的项目是 client_id 和 client_email.

The p12 certificate and user values are stored on the server. All "ini" files have the same structure of values, client_id, client_email, scope and query filter. In all cases the only item that changes between the files is the client_id and client_email.

我的代码如下:

    <?php

 include (__DIR__ . "/google-api-php-client/autoload.php");

 google_api_php_client_autoload("Google_Auth_AssertionCredentials");
 google_api_php_client_autoload("Google_Client");
 google_api_php_client_autoload("Google_Service_Drive");
 google_api_php_client_autoload("Google_Service_OAuth2");

 $type = $_GET['type'];
 $path = __DIR__ . "/secure/";
 $certificate = $path . $type . ".p12";
 $ini_path = $path . $type . ".ini";

 $ini = parse_ini_file($ini_path);
 $service_scope = $ini['scope'];
 $service_account_id = $ini['id'];
 $service_account_email = $ini['email'];
 $service_query = $ini['q'];

 $service_account_key = file_get_contents($certificate);
 $credentials = new Google_Auth_AssertionCredentials(
  $service_account_email,
  array($service_scope),
  $service_account_key
 );
 $credentials -> sub = $service_account_email;

 $google_client = new Google_Client();

 $google_client -> setAssertionCredentials($credentials);
 if ($google_client -> getAuth() -> isAccessTokenExpired()) {
  $google_client -> getAuth() -> refreshTokenWithAssertion(); **//FAILS HERE**
 }  

 $drive = new Google_Service_Drive($google_client);

 $result = array();
 $pageToken = NULL;

 do {
  try {
   $parameters = array();
   if ($pageToken) {
    $parameters['pageToken'] = $pageToken;
   }
   $parameters['q'] = $service_query;

   $files = $drive -> files -> listFiles($parameters);

   $result = array_merge($result, $files -> getItems());
   $pageToken = $files -> getNextPageToken();
  } catch (Exception $e) {
   print "An error occurred: " . $e -> getMessage();
   $pageToken = NULL;
  }
 } while ($pageToken);

 echo json_encode($result) . "
";
?>

每个ini文件的结构如下

Each ini file is structured as follows

id="35{code}.apps.googleusercontent.com"
email="35{code}@developer.gserviceaccount.com"
scope="https://www.googleapis.com/auth/drive.readonly"
q="mimeType != 'application/vnd.google-apps.folder'"

我无法弄清楚为什么当我对所有服务帐户都进行了相同的过程时,这对一个服务帐户而不是其他服务帐户有效.任何想法和帮助表示赞赏.

What I just cannot work out is why this works for one service account and not the others when I have gone through the same process for all of them. Any ideas and help appreciated.

推荐答案

感谢您的这篇文章以及您对Resolved by remove the line $credentials -> sub = $service_account_email;"

Thanks for this post and your comment about "Resolved by removing the line $credentials -> sub = $service_account_email;"

我面临着类似的问题 这里.显然, $credentials ->sub = $service_account_email 仅适用于在 Google Developers Console 中创建的第一个/主要服务帐户.除此之外,它还会在某些 OAuth2 范围内产生意外错误(就像我在 Fusion Tables 中遇到的那样).

I am facing a similar issue here. Apparently, $credentials -> sub = $service_account_email is only accepted for the first/primary service account created in the Google Developers Console. Besides that, it will also produce unexpected errors with certain OAuth2 scopes (as what I encountered with Fusion Tables).

因此,这里是一般建议:

Hence, here is the general advise:

不要包含 $credentials ->sub = $service_account_email 不必要.

仅当您尝试冒充差异用户(条件是适当的设置具有已在 Google Apps 管理控制台中正确完成).

尽管在某些情况下它可能不会产生任何错误,但在将服务帐户本身的电子邮件地址包含在 JWT 声明集中作为sub"字段的值时,会出现一些意外行为.

DO NOT include $credentials -> sub = $service_account_email unnecessarily.

Only do this when you are trying to impersonating a difference user (with the condition that the appropriate setup has been correctly done in Google Apps Admin Console).

Even though it may not produce any error under certain cases, there are some unexpected behaviors when including an email address of the service account itself in the JWT claim set as the value of the "sub" field.

相关文章