Menghubungkan ke Layanan non-Google dari add-on Google Workspace

Tetap teratur dengan koleksi Simpan dan kategorikan konten berdasarkan preferensi Anda.

Project Google Workspace add-on dapat terhubung langsung ke banyak produk Google dengan layanan bawaan dan lanjutan pada Apps Script.

Anda juga dapat mengakses API dan layanan non-Google. Jika layanan tidak memerlukan otorisasi, Anda biasanya dapat membuat permintaan UrlFetch yang sesuai, lalu meminta add-on menafsirkan respons.

Namun, jika layanan non-Google tersebut memerlukan otorisasi, Anda harus mengonfigurasi OAuth untuk layanan tersebut. Anda dapat mempermudah proses ini menggunakan library OAuth2 untuk Apps Script (ada juga versi OAuth1).

Menggunakan layanan OAuth

Saat menggunakan objek layanan OAuth untuk terhubung ke layanan non-Google, add-onGoogle Workspace harus mendeteksi kapan otorisasi diperlukan dan, saat ya, memanggil alur otorisasi.

Alur otorisasi terdiri dari:

  1. Memberi tahu pengguna bahwa autentikasi diperlukan dan memberikan link untuk memulai proses.
  2. Memperoleh otorisasi dari layanan non-Google.
  3. Me-refresh add-on untuk mencoba kembali mengakses resource yang dilindungi.

Saat otorisasi non-Google diperlukan, infrastruktur add-on Google Workspace akan menangani detail ini. Add-on hanya perlu mendeteksi saat otorisasi diperlukan dan memanggil alur otorisasi jika diperlukan.

Mendeteksi bahwa otorisasi diperlukan

Permintaan mungkin tidak memiliki otorisasi untuk mengakses resource yang dilindungi karena berbagai alasan, seperti:

  • Token akses belum dibuat atau habis masa berlakunya.
  • Token akses tidak mencakup resource yang diminta.
  • Token akses tidak mencakup cakupan yang diperlukan dari permintaan.

Kode add-on akan mendeteksi kasus ini. Fungsi hasAccess() library OAuth dapat memberi tahu Anda apakah saat ini Anda memiliki akses ke layanan. Atau, saat menggunakan permintaan UrlFetchApp fetch(), Anda dapat menyetel parameter muteHttpExceptions ke true. Hal ini mencegah permintaan menampilkan pengecualian saat kegagalan permintaan dan memungkinkan Anda memeriksa kode dan konten respons permintaan dalam objek HttpResponse yang ditampilkan.

Saat mendeteksi bahwa otorisasi diperlukan, add-on akan memicu alur otorisasi.

Memanggil alur otorisasi

Anda memanggil alur otorisasi dengan menggunakan Layanan kartu untuk membuat objek AuthorizationException, menyetel propertinya, lalu memanggil fungsi throwException(). Sebelum melempar pengecualian, Anda harus memberikan hal berikut:

  1. Wajib. URL otorisasi. Ini ditentukan oleh layanan non-Google dan merupakan lokasi tujuan diarahkannya pengguna saat alur otorisasi dimulai. Anda menetapkan URL ini menggunakan fungsi setAuthorizationUrl().
  2. Wajib. String nama tampilan resource. Mengidentifikasi resource kepada pengguna saat otorisasi diminta. Anda menetapkan nama ini menggunakan fungsi setResourceDisplayName().
  3. Nama fungsi callback yang membuat perintah otorisasi kustom. Callback ini menampilkan array objek Card build yang menulis UI untuk menangani otorisasi. Cara ini bersifat opsional; jika tidak, kartu otorisasi default akan digunakan. Anda menetapkan fungsi callback menggunakan fungsi setCustomUiCallback().

Contoh konfigurasi OAuth non-Google

Contoh kode ini menunjukkan cara mengonfigurasi add-on untuk menggunakan API non-Google yang memerlukan OAuth. Layanan ini menggunakan OAuth2 untuk Apps Script guna membuat layanan untuk mengakses API.

/**
 * 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("Display name to show to the user")
        .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('SERVICE_NAME')
      .setAuthorizationBaseUrl('SERVICE_AUTH_URL')
      .setTokenUrl('SERVICE_AUTH_TOKEN_URL')
      .setClientId('CLIENT_ID')
      .setClientSecret('CLIENT_SECRET')
      .setScope('SERVICE_SCOPE_REQUESTS')
      .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();
}

Membuat perintah otorisasi khusus

kartu otorisasi layanan non-Google

Secara default, permintaan otorisasi tidak memiliki branding apa pun dan hanya menggunakan string nama tampilan untuk menunjukkan resource yang diupayakan untuk diakses oleh add-on. Namun, add-on Anda dapat menentukan kartu otorisasi yang disesuaikan yang memiliki tujuan yang sama dan dapat menyertakan informasi dan branding tambahan.

Anda menentukan perintah kustom dengan mengimplementasikan fungsi callback UI kustom yang menampilkan array objek Card yang dibuat. Array ini hanya boleh berisi satu kartu. Jika disediakan lebih banyak, header-nya akan ditampilkan dalam daftar, yang dapat mengakibatkan pengalaman pengguna yang membingungkan.

Kartu yang ditampilkan harus melakukan hal berikut:

  • Perjelas pengguna bahwa add-on meminta izin untuk mengakses layanan non-Google atas nama mereka.
  • Jelaskan apa yang dapat dilakukan add-on jika diizinkan.
  • Berisi tombol atau widget serupa yang mengarahkan pengguna ke URL otorisasi layanan. Pastikan fungsi widget ini jelas bagi pengguna.
  • Widget di atas harus menggunakan setelan OnClose.RELOAD_ADD_ON di objek OpenLink untuk memastikan add-on dimuat ulang setelah otorisasi diterima.
  • Semua link yang dibuka dari permintaan otorisasi harus menggunakan HTTPS.

Anda mengarahkan alur otorisasi untuk menggunakan kartu dengan memanggil fungsi setCustomUiCallback() pada objek AuthorizationException.

Contoh berikut menunjukkan fungsi callback perintah otorisasi kustom:

/**
 * Returns an array of cards that comprise the customized authorization
 * prompt. Includes a button that opens the proper authorization link
 * for a non-Google service.
 *
 * When creating the text button, using the
 * setOnClose(CardService.OnClose.RELOAD_ADD_ON) function forces the add-on
 * to refresh once the authorization flow completes.
 *
 * @return {Card[]} The card representing the custom authorization prompt.
 */
function create3PAuthorizationUi() {
  var service = getOAuthService();
  var authUrl = service.getAuthorizationUrl();
  var authButton = CardService.newTextButton()
      .setText('Begin Authorization')
      .setAuthorizationAction(CardService.newAuthorizationAction()
          .setAuthorizationUrl(authUrl));

  var promptText =
      'To show you information from your 3P account that is relevant' +
      ' to the recipients of the email, this add-on needs authorization' +
      ' to: <ul><li>Read recipients of the email</li>' +
      '         <li>Read contact information from 3P account</li></ul>.';

  var card = CardService.newCardBuilder()
      .setHeader(CardService.newCardHeader()
          .setTitle('Authorization Required'))
      .addSection(CardService.newCardSection()
          .setHeader('This add-on needs access to your 3P account.')
          .addWidget(CardService.newTextParagraph()
              .setText(promptText))
          .addWidget(CardService.newButtonSet()
              .addButton(authButton)))
      .build();
  return [card];
}

/**
 * When connecting to the non-Google service, pass the name of the
 * custom UI callback function to the AuthorizationException object
 */
function accessProtectedResource(url, method_opt, headers_opt) {
  var service = getOAuthService();
  if (service.hasAccess()) {
    // Make the UrlFetch request and return the result.
    // ...
  } else {
    // Invoke the authorization flow using a custom authorization
    // prompt card.
    CardService.newAuthorizationException()
        .setAuthorizationUrl(service.getAuthorizationUrl())
        .setResourceDisplayName("Display name to show to the user")
        .setCustomUiCallback('create3PAuthorizationUi')
        .throwException();
  }
}

Mengelola login pihak ketiga di Google Workspace aplikasi

Salah satu aplikasi umum untuk Google Workspace add-on adalah menyediakan antarmuka untuk berinteraksi dengan sistem pihak ketiga dari dalam Google Workspace aplikasi host. Library OAuth2 untuk Apps Script dapat membantu Anda membuat dan mengelola koneksi ke layanan pihak ketiga.

Sistem pihak ketiga sering kali mengharuskan pengguna untuk login menggunakan ID pengguna, sandi, atau kredensial lainnya. Saat pengguna login ke layanan pihak ketiga saat dia menggunakan satu Google Workspace host, Anda harus memastikan bahwa dia tidak perlu login lagi saat beralih ke hostGoogle Workspace lain. Untuk mencegah permintaan login berulang, gunakan properti pengguna atau token ID. Hal ini dijelaskan di bagian berikut.

Properti pengguna

Anda dapat menyimpan data login pengguna di properti pengguna Apps Script. Misalnya, Anda dapat membuat JWT Anda sendiri dari layanan login mereka dan mencatatnya di properti pengguna, atau mencatat nama pengguna dan sandi untuk layanan mereka.

Properti pengguna dicakup sedemikian rupa sehingga hanya dapat diakses oleh pengguna tersebut dalam skrip add-on Anda. Pengguna lain dan skrip lainnya tidak dapat mengakses properti ini. Lihat PropertiesService untuk detail selengkapnya.

Token ID

Anda dapat menggunakan token ID Google sebagai kredensial login untuk layanan Anda. Ini adalah cara untuk mencapai single sign-on. Pengguna sudah login ke Google karena mereka menggunakan aplikasi host Google.