【问题标题】:Google Seach Console API authorization issue with service account服务帐户的 Google Search Console API 授权问题
【发布时间】:2020-01-24 18:43:02
【问题描述】:

我正在尝试通过 http 请求从 Google 搜索控制台 (GSC) 获取数据。

我正在使用带有 javascript 的 google app Maker。

出于我的目的,我使用的是服务帐户,所有范围都已为该帐户设置。

我已经复制了@Morfinismo 提供的代码。

/*********** SERVICE ACCOUNT CONFIGURATION USING THE OAUTH LIBRARY ***********
** All of the values are obtained from the .json file that is downloaded at
** the time of the service account creation
** Ref: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
** Ref: https://github.com/googlesamples/apps-script-oauth2
*/


var accessData = {
  "private_key" : "-----BEGIN PRIVATE KEY-----THE KEY-----END PRIVATE KEY-----\n",
  "client_email" : "searchconsolebot@project-id-xxxxxxxxxxxxxxx.iam.gserviceaccount.com",
  "user_email" : "user@domain.com" // Why do we need a user mail ?
};


var scopes = ["https://www.googleapis.com/auth/webmasters", "https://www.googleapis.com/auth/webmasters.readonly"]; //GSC api scope
scopes = scopes.join(" "); //join all scopes into a space separated string

function getOAuthService(user) {
  console.log("je passe par getOAuthService");
  user = user || accessData.user_email;
  console.log("user: " + user);
  return OAuth2.createService("GSC_Service_Account")
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(accessData.private_key)
    .setIssuer(accessData.client_email)
    .setSubject(user)
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setCache(CacheService.getUserCache())
    .setParam('access_type', 'offline')
    .setScope(scopes);
}


function reset(user) {
  var service = getOAuthService(user);
  console.log("service: " + service);
  service.reset();
  return service;
}


function getToken(userEmail){
  var totoken = reset(userEmail).getAccessToken();
  console.log(totoken);
  return reset(userEmail).getAccessToken();
}


function getGCSUrlData(urlGiven){
  var token = getToken();
  if(token){
    var reqBody = {
      startDate: "2019-01-01",
      endDate: "2020-01-23"
    };
    var options = {
      method : 'POST',           
      headers : {
        Authorization : 'Bearer ' + token,
      },
      contentType: 'application/json',
      payload: JSON.stringify(reqBody),
      muteHttpExceptions: true,
    };
    var url = "https://www.googleapis.com/webmasters/v3/sites/" + encodeURIComponent(urlGiven) + "/searchAnalytics/query";
    var response = UrlFetchApp.fetch(url, options);
    console.log(response);
  }
}

使用 OAuth 库看起来非常棒,但它确实返回了一个错误

Error: Access not granted or expired. at getToken (Service_Account_Config:46)

我还注意到getToken() 方法需要一个参数,但是在调用它时我们没有提供任何参数是正常的吗? 为什么我们需要一个 user_email ,因为我们使用的是服务帐户? 那么我应该为 user_email 输入哪个电子邮件?

非常感谢有关此问题的一些帮助以及了解此类问题的任何建议。

非常感谢, 杰基

【问题讨论】:

  • 刚刚在 firefox 上试用过,它运行良好...为什么它不能在 chrome 上运行?谢谢
  • 我已经尝试检查 google googleapis.com/oauth2/v4/token 提供的链接,但它似乎不存在可能是这个问题吗?
  • 再次配置我的服务帐户后它终于可以工作了!

标签: javascript api oauth-2.0 google-app-maker


【解决方案1】:

使用OAuth2 Library for AppsScript 时,与服务帐户集成非常容易。步骤如下:

1.) 在服务器端脚本中添加以下内容:

/*********** SERVICE ACCOUNT CONFIGURATION USING THE OAUTH LIBRARY ***********
** All of the values are obtained from the .json file that is downloaded at
** the time of the service account creation
** Ref: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
** Ref: https://github.com/googlesamples/apps-script-oauth2
*/

var accessData= {
  "private_key": "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n",
  "client_email": "service-account825@08012018.iam.gserviceaccount.com",
  "user_email": "user@domain.com"
};

var scopes = ["https://www.googleapis.com/auth/webmasters", "https://www.googleapis.com/auth/webmasters.readonly"]; //drive api scope
scopes = scopes.join(" "); //join all scopes into a space separated string

function getOAuthService(user) {
  user = user || accessData.user_email;
  return OAuth2.createService("Service Account")
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(accessData.private_key)
    .setIssuer(accessData.client_email)
    .setSubject(user)
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setCache(CacheService.getUserCache())
    .setParam('access_type', 'offline')
    .setScope(scopes);
}


function reset(user) {
  var service = getOAuthService(user);
  service.reset();
  return service;
}


function getToken(userEmail){
  return reset(userEmail).getAccessToken();
}

然后您可以通过执行以下操作来调用您需要的服务:

function getGCSUrlData(urlGiven){
  var token = getToken();
  if(token){
    var reqBody = {
      startDate: "2020-01-01",
      endDate: "2020-01-23"
    };
    var options = {
      method : 'POST',           
      headers : {
        Authorization : 'Bearer ' + token,
      },
      contentType: 'application/json',
      payload: JSON.stringify(reqBody),
      muteHttpExceptions: true,
    };
    var url = "https://www.googleapis.com/webmasters/v3/sites/" + encodeURIComponent(urlGiven) + "/searchAnalytics/query";
    var response = UrlFetchApp.fetch(url, options);
    console.log(response);
  }
}

【讨论】:

  • 感谢您的回答。我设法让它工作,但你的例子真的很棒,我现在对这样做的方式的理解真的好多了。我实际上正在尝试更新它以使用服务帐户(出于我的目的)我想我需要打开一个新线程,因为它不是同一个问题。
  • @LIMJacky 使用服务帐户会好很多,只需编辑您的问题,我会发布解决方案。
  • @LIMJacky 更新了答案。希望对您有所帮助!
  • 感谢您的回答@Morfinismo,我现在就试试!!
  • 我已经尝试了代码,但它确实返回了一个错误,说明访问权限未被授予或令牌已过期。我同时更新了帖子,感谢您的帮助@Morfinismo。
猜你喜欢
  • 2013-08-21
  • 1970-01-01
  • 2020-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-22
  • 1970-01-01
  • 2018-09-03
相关资源
最近更新 更多