“需要授权才能执行该操作”消息,即使在单击“允许”之后也是如此

Posted

技术标签:

【中文标题】“需要授权才能执行该操作”消息,即使在单击“允许”之后也是如此【英文标题】:"Authorisation is required to perform that action" message, even after clicking "Allow" 【发布时间】:2018-09-04 14:44:42 【问题描述】:

我最近在授权一个新的 Google App Script 项目时遇到了问题,特别是一个使用 Cloud SQL 管理 API 的项目。

以前授权的 GAS 项目中存在相同的代码并且工作正常,但如果我复制 GAS 项目并第一次尝试运行某个函数,我将无法完成授权过程。下面列出了我正在浏览的屏幕:

    需要授权。 - 点击“查看权限” 选择一个帐户来授权 Google 项目。 - 点击我的帐户 此应用未经验证! - 点击“前往项目 (不安全)” Google 项目想要访问此范围列表。- 点击“允许” 需要授权才能执行该操作。

警告屏幕 (3) 是该过程的最新添加。我不记得在今年早些时候创建和运行新项目时遇到过它。我想知道 Google 最近是否对其 OAuth2.0 的安全实施进行了任何更改。

此外,此问题似乎只影响对 Cloud SQL 管理 API 的 REST 调用。在上面提到的同一个项目中,我能够运行将数据写入同一个 Google 项目中的 BigQuery 表的函数,该项目也托管 Cloud SQL 实例。显然,一些范围和代码可以工作。

“https://www.googleapis.com/auth/sqlservice.admin”范围包含在我请求并批准的列表中。我什至尝试手动编辑 URL 以添加更多请求的范围,但它仍然没有让我通过“需要授权才能执行该操作”屏幕。

有人有什么想法吗?

编辑:

触发身份验证的相关代码。

// Function to get the ip address of a given CloudSQL instance
function _getInstanceIpAddress_(projectId, sqlInstance) 

  var token = _getAuthenticationToken_();

  // Create the header authorisation  
  var headers = 
    "Authorization": "Bearer " + token
  ;

  // Create the Cloud SQL instances get parameters
  var parameters = 
    "method": "get",    
    "headers": headers,
    "instance": sqlInstance,
    "project": projectId,
    "muteHttpExceptions": true
  ;

  // Create the url of the sql instances get API    
  var api = "https://www.googleapis.com/sql/v1beta4/projects/" + projectId + "/instances/" + sqlInstance + "?fields=ipAddresses";   

  try 
    // Use the url fetch service to issue the https request and capture the response
    var response = UrlFetchApp.fetch(api, parameters);    

    // Extract the ip address of the instance from the response
    var content = JSON.parse(response.getContentText());

    return content.ipAddresses[0].ipAddress; 
   catch(err) 
    _log_('ERROR', 'Getting ' + sqlInstance + ' instance ip address failed: ' + err);
    return null;
  


function _getAuthenticationToken_() 
  // Check we have access to the service
  var service = getService();
  if (!service.hasAccess()) 
    var authorizationUrl = service.getAuthorizationUrl();
    _log_('INFO', 'Open the following URL and re-run the script: ' + authorizationUrl);
    return;
  

  Logger.log('Passed Authentication');

  //Get the Access Token
  return service.getAccessToken();

  function getService() 
    // Create a new service with the given name. The name will be used when
    // persisting the authorized token, so ensure it is unique within the
    // scope of the property store.
    return OAuth2.createService('companyName-dev-service')

    // Set the endpoint URLs, which are the same for all Google services.
    .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')

    // Set the client ID and secret, from the Google Developers Console.
    .setClientId(CLIENT_ID)
    .setClientSecret(CLIENT_SECRET)

    // Set the name of the callback function in the script referenced
    // above that should be invoked to complete the OAuth flow.
    .setCallbackFunction('authCallback')

    // Set the property store where authorized tokens should be persisted.
    .setPropertyStore(PropertiesService.getUserProperties())

    // Set the scopes to request (space-separated for Google services).
    // this is admin access for the sqlservice and access to the cloud-platform:
    .setScope(
      'https://www.googleapis.com/auth/sqlservice.admin ' + 
      'https://www.googleapis.com/auth/cloud-platform')

    //Removed because this Should be covered by cloud-platform
    //'https://www.googleapis.com/auth/devstorage.read_write ' 

    // Below are Google-specific OAuth2 parameters.

    // Sets the login hint, which will prevent the account chooser screen
    // from being shown to users logged in with multiple accounts.
    .setParam('login_hint', Session.getActiveUser().getEmail())

    // Requests offline access.
    .setParam('access_type', 'offline')

    // Forces the approval prompt every time. This is useful for testing,
    // but not desirable in a production application.
    .setParam('approval_prompt', 'force');
  

  function authCallback(request) 
    var cloudSQLService = getService();
    var isAuthorized = cloudSQLService.handleCallback(request);

    if (isAuthorized) 
      _log_('INFO', 'Access Approved');
      return htmlService.createHtmlOutput('Success! You can close this tab.');
     else 
      _log_('INFO', 'Access Denied');
      return HtmlService.createHtmlOutput('Denied. You can close this tab');
    
  

【问题讨论】:

发布一个 MCVE 示例和重现说明? 【参考方案1】:

我们在使用 Google Compute Engine API 时遇到了类似的问题。根据this article 在appsscript.json 文件中明确设置范围为我们解决了这个问题:

"oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets.readonly",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/script.container.ui",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/compute",
    "https://www.googleapis.com/auth/cloud-platform"
  ],

【讨论】:

谢谢!这行得通。 这似乎是一个 2 部分范围的问题。我扩展了清单中的范围并将它们手动添加到请求 URL 中,这停止了“执行该操作需要授权”。消息出现。【参考方案2】:

如果您回想大约一年前,您可能还记得 Massive Phishing Attack Targets Gmail Users 您看到的是 google 对此的回应。

使用特定范围的网络凭据需要 Google 批准,然后创建相关凭据的开发人员才能使用它。谷歌表示,通常需要一周左右的时间才能获得批准。

你之前没见过,因为这是最近才出现的应用脚本OAuth client verification

自 2017 年 7 月 18 日起,请求某些敏感 OAuth 范围的 Google OAuth 客户端将接受 Google 的审核。

【讨论】:

OP 的真正问题有点隐蔽——在 oauth 流程中点击允许会生成授权不足的错误,而不是授权项目。 如果是这种情况,他可能没有授予访问权限。我今天早些时候用这个没有错误 感谢您的帮助,当网络钓鱼攻击首次出现时,我们注意到安全限制发生了变化,并通过加入 "risky-access-by-unreviewed-apps" Google 解决了这个问题团体。看起来这已经不够了。既然我是开发人员,它不应该为我工作吗?我会考虑获得 Google 的批准,尽管它确实让人感觉参与度很高,特别是如果开发人员只是为小型 GCP 任务编写小脚本以在他们自己的公司域下运行自己。 假设您使用用于创建凭据的同一帐户登录,它应该对您有用,我将在早上发布一些屏幕截图

以上是关于“需要授权才能执行该操作”消息,即使在单击“允许”之后也是如此的主要内容,如果未能解决你的问题,请参考以下文章

VB.NET:即使在您关闭程序之后,您如何显示“您受到保护”消息?

Facebook隐私政策不允许消息

IE CORS - 即使指定了标头,访问控制允许标头错误

如何允许 链接服务器OLE DB 访问接口 "SQLNCLI10" 返回了消息 "登录超时已过期"。

self.close() 将关闭程序,即使 closeEvent() 内部有 self.ignore()

以编程方式鼠标单击另一个窗口