Gmail加载项:未触发Oauth [英] Gmail Add-On: Oauth not being triggered

查看:51
本文介绍了Gmail加载项:未触发Oauth的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,测试"按钮触发一个函数,该函数调用外部端点以加载数据.但是,单击该按钮后什么也没有发生,并且在控制台区域出现 400 错误,提示 Invalid Argument .

In the code below, 'Test' button triggers a function which calls an external endpoint to load data. However, nothing happens when the button is clicked and I get a 400 error in the console area saying Invalid Argument.

Code.gs

function buildAddOn(e) {
  // Create a section for that contains all user Labels.
  var section = CardService.newCardSection()  
  var action = CardService.newAction()
        .setFunctionName("testCall");

  var button = CardService.newTextButton().setText('Test').setOnClickAction(action);
  section.addWidget(CardService.newButtonSet().addButton(button)); 

//  section.addWidget(CardService.newTextParagraph()
//    .setText("This is a text paragraph widget. Multiple lines are allowed if needed.");)

  // Build the main card after adding the section.
  var card = CardService.newCardBuilder()
    .setHeader(CardService.newCardHeader()
    .setTitle('Authentication Card')
    .setImageUrl('https://www.gstatic.com/images/icons/material/system/1x/label_googblue_48dp.png'))
    .addSection(section)
    .build();

  return [card];
}

function testCall(){
  console.log("test");
  var data = accessProtectedResource('https://api.ssdf.io/v1.0/asd/4/174203','get');
  return CardService.newActionResponseBuilder()
      .setNotification(CardService.newNotification()
          .setType(CardService.NotificationType.INFO)
          .setText(data))
      .build();
}

authService.gs

/**
 * Attempts to access a non-Google API using a constructed service
 * object.
 *
 * If your add-on needs access to non-Google APIs that require OAuth,
 * you need to implement this method. You can use the OAuth1 and
 * OAuth2 Apps Script libraries to help implement it.
 *
 * @param {String} url         The URL to access.
 * @param {String} method_opt  The HTTP method. Defaults to GET.
 * @param {Object} headers_opt The HTTP headers. Defaults to an empty
 *                             object. The Authorization field is added
 *                             to the headers in this method.
 * @return {HttpResponse} the result from the UrlFetchApp.fetch() call.
 */
function accessProtectedResource(url, method_opt, headers_opt) {
  var service = getOAuthService();
  var maybeAuthorized = service.hasAccess();
  if (maybeAuthorized) {
    // A token is present, but it may be expired or invalid. Make a
    // request and check the response code to be sure.

    // Make the UrlFetch request and return the result.
    var accessToken = service.getAccessToken();
    var method = method_opt || 'get';
    var headers = headers_opt || {};
    headers['Authorization'] =
        Utilities.formatString('Bearer %s', accessToken);
    var resp = UrlFetchApp.fetch(url, {
      'headers': headers,
      'method' : method,
      'muteHttpExceptions': true, // Prevents thrown HTTP exceptions.
    });

    var code = resp.getResponseCode();
    if (code >= 200 && code < 300) {
      return resp.getContentText("utf-8"); // Success
    } else if (code == 401 || code == 403) {
       // Not fully authorized for this action.
       maybeAuthorized = false;
    } else {
       // Handle other response codes by logging them and throwing an
       // exception.
       console.error("Backend server error (%s): %s", code.toString(),
                     resp.getContentText("utf-8"));
       throw ("Backend server error: " + code);
    }
  }

  if (!maybeAuthorized) {
    // Invoke the authorization flow using the default authorization
    // prompt card.
    CardService.newAuthorizationException()
        .setAuthorizationUrl(service.getAuthorizationUrl())
        .setResourceDisplayName("Login to ....")
        .throwException();
  }
}

/**
 * Create a new OAuth service to facilitate accessing an API.
 * This example assumes there is a single service that the add-on needs to
 * access. Its name is used when persisting the authorized token, so ensure
 * it is unique within the scope of the property store. You must set the
 * client secret and client ID, which are obtained when registering your
 * add-on with the API.
 *
 * See the Apps Script OAuth2 Library documentation for more
 * information:
 *   https://github.com/googlesamples/apps-script-oauth2#1-create-the-oauth2-service
 *
 *  @return A configured OAuth2 service object.
 */
function getOAuthService() {
  return OAuth2.createService('auth')
      .setAuthorizationBaseUrl('https://app.ss.io/oauth/authorize')
      .setTokenUrl('https://api.ss.io/oauth/token')
      .setClientId('2361c9fbc5ba4b88813a3ef')
      .setClientSecret('f5d3a04f4asda30a52830e230e43727')
      .setScope('1')
      .setCallbackFunction('authCallback')
      .setCache(CacheService.getUserCache())
      .setPropertyStore(PropertiesService.getUserProperties());
}

/**
 * Boilerplate code to determine if a request is authorized and returns
 * a corresponding HTML message. When the user completes the OAuth2 flow
 * on the service provider's website, this function is invoked from the
 * service. In order for authorization to succeed you must make sure that
 * the service knows how to call this function by setting the correct
 * redirect URL.
 *
 * The redirect URL to enter is:
 * https://script.google.com/macros/d/<Apps Script ID>/usercallback
 *
 * See the Apps Script OAuth2 Library documentation for more
 * information:
 *   https://github.com/googlesamples/apps-script-oauth2#1-create-the-oauth2-service
 *
 *  @param {Object} callbackRequest The request data received from the
 *                  callback function. Pass it to the service's
 *                  handleCallback() method to complete the
 *                  authorization process.
 *  @return {HtmlOutput} a success or denied HTML message to display to
 *          the user. Also sets a timer to close the window
 *          automatically.
 */
function authCallback(callbackRequest) {
  var authorized = getOAuthService().handleCallback(callbackRequest);
  if (authorized) {
    return HtmlService.createHtmlOutput(
      'Success! <script>setTimeout(function() { top.window.close() }, 1);</script>');
  } else {
    return HtmlService.createHtmlOutput('Denied');
  }
}

/**
 * Unauthorizes the non-Google service. This is useful for OAuth
 * development/testing.  Run this method (Run > resetOAuth in the script
 * editor) to reset OAuth to re-prompt the user for OAuth.
 */
function resetOAuth() {
  getOAuthService().reset();
}

推荐答案

函数 getOAuthService()中的所有URL必须是示例的原始google-URL:

All URLs in the function getOAuthService() have to be the original google-URLs of the example:

      // 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 scopes to request (space-separated for Google services).
      .setScope('https://www.googleapis.com/auth/drive')

也许可以更改后一个,但仅更改路径而不是域,并且您必须查看API是否以及如何调整.同样,该范围参数在您的示例中有所不同,但是我不知道是否可以接受"1".

It might be possible to change the latter one, but only the path, not the domain, and you've to look in the API if and how it is adjustable. Also this scope-parameter differs in your example, but I don't know if '1' could be accepted.

如果授予访问权限,但不涉及验证身份验证,则您自己的应用程序会收到反馈.因此,您还需要获取访问令牌,我会在您的代码中看到它: var accessToken = service.getAccessToken(); ,在示例中看起来有点不同:

Your own application get's a feedback if access is granted but is not involved in validating the authentication. Therefore you also need to get the access-token, I see it in your code: var accessToken = service.getAccessToken();, in the example it looks a bit different:

function makeRequest() {
  var driveService = getDriveService();
  var response = UrlFetchApp.fetch('https://www.googleapis.com/drive/v2/files?maxResults=10', {
    headers: {
      Authorization: 'Bearer ' + driveService.getAccessToken()
    }
  });
  // ...
}

参见带有 Authorization:'Bearer'+ driveService.getAccessToken()的行.

未(也不应该)将您自己的服务器配置为处理身份验证请求,因此会抛出

Your own server isn't (and shouldn't be) configured to handle authentication requests and therefore throws the 400 error. The API is built for use by Javascript on client-side, therefore I advise not to use it to authenticate on an own server. Nevertheless below I listed APIs for usage on your own server.

使用您自己的服务器进行身份验证
如果您不建议使用google服务器进行身份验证,那么随着服务器配置(apache,nginx等)和服务器端编程语言(PHP,Python,...).

Using your own server for authentication
If you dismiss my advise to use the google-servers for authentication, then the scope of the tagged issues is getting larger, as server-configuration (apache, nginx, ...) and server-side programming-languages (PHP, Python, ...) might be involved.

然后,您必须调试标头,将其准确发送到服务器的原因以及服务器无法处理的原因.您可以在浏览器的开发人员工具(网络面板)中调试请求和响应,并检查服务器的错误文件.

You've to debug the headers then, what is sent exactly to the server and why the server can't handle it. You can debug the request and response in the browser's developer-tool (network panel) and check the error-files of the server.

服务器必须自己获取google-service,然后执行

The server has to acquire the google-service then by itself and do what would be done in frontend only by javascript if you'd follow the example you linked in your code.

在此示例中,进行了三个服务器请求:
-一个进行身份验证
-一个获得身份验证令牌的人
-获得受保护服务的人
您必须记住,然后必须由您自己的服务器完成所有三个步骤,并且您的服务器必须能够对所有三种请求类型进行回答.
一个重要的问题可能是三个请求中的哪个正在产生错误?

In the example are three server-request made:
- one to authenticate
- one to get the authentication-token
- one to get the protected service
You've to keep in mind that all three steps have to be done then by your own server and that your server has to be able to answer on all three request-types.
An important question might be which of the three requests is producing the error?

您应该扩展您的问题,然后再发现与服务器通信有关的详细问题.

You should extend your question then with the detailed problems you discover concerning communication with your server.

服务器端OAuth身份验证的API和示例
PHP:
https://developers.google.com/api-客户端库/php/auth/web-app
Python: https://developers.google.com/api-客户端库/python/auth/web-app
Ruby: https://developers.google.com/api-客户端库/ruby​​/auth/web-app
NodeJ: https://developers.google.com/apps-script/api/quickstart/nodejs
Java: https://developers.google.com/api-client-library/java/google-oauth-java-client/
转到: https://github.com/googleapis/google-api-go-client
.NET: https://developers.google.com/api-client-library/dotnet/apis/oauth2/v2

这篇关于Gmail加载项:未触发Oauth的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆