Verbindung zu Diensten von Drittanbietern über ein Google Workspace-Add-on herstellen

Ihr Google Workspace-Add-on-Projekt kann über die integrierten und erweiterten Dienste von Apps Script eine direkte Verbindung zu vielen Google-Produkten herstellen.

Sie können auch auf APIs und Dienste von Drittanbietern zugreifen. Wenn der Dienst keine Autorisierung erfordert, können Sie in der Regel einfach eine entsprechende UrlFetch-Anfrage stellen und dann das Add-on die Antwort interpretieren lassen.

Wenn der Nicht-Google-Dienst jedoch eine Autorisierung erfordert, müssen Sie OAuth für diesen Dienst konfigurieren. Sie können diesen Vorgang vereinfachen, indem Sie die Bibliothek OAuth2 for Apps Script verwenden. Es gibt auch eine OAuth1-Version.

OAuth-Dienst verwenden

Wenn Sie ein OAuth-Dienstobjekt verwenden, um eine Verbindung zu einem Nicht-Google-Dienst herzustellen, muss das Google Workspace-Add-on erkennen, wann eine Autorisierung erforderlich ist, und den Vorgang gegebenenfalls aufrufen.

Der Autorisierungsvorgang umfasst Folgendes:

  1. Der Nutzer wird darüber informiert, dass eine Authentifizierung erforderlich ist, und ihm einen Link zum Starten des Prozesses senden.
  2. Autorisierung von einem Drittanbieterdienst erhalten
  3. Aktualisieren Sie das Add-on, um noch einmal auf die geschützte Ressource zuzugreifen.

Wenn eine Autorisierung nicht von Google erforderlich ist, verarbeitet die Infrastruktur des Google Workspace-Add-ons diese Details. Das Add-on muss nur erkennen, wann eine Autorisierung erforderlich ist, und den Autorisierungsvorgang bei Bedarf aufrufen.

Erkennen, dass Autorisierung erforderlich ist

Eine Anfrage hat möglicherweise aus verschiedenen Gründen keine Autorisierung für den Zugriff auf eine geschützte Ressource, z. B.:

  • Das Zugriffstoken wurde noch nicht generiert oder ist abgelaufen.
  • Das Zugriffstoken deckt die angeforderte Ressource nicht ab.
  • Das Zugriffstoken deckt nicht die erforderlichen Bereiche der Anfrage ab.

Der Add-on-Code sollte solche Fälle erkennen. Die Funktion hasAccess() der OAuth-Bibliothek kann Ihnen mitteilen, ob Sie derzeit Zugriff auf einen Dienst haben. Alternativ können Sie bei UrlFetchApp fetch()-Anfragen den Parameter muteHttpExceptions auf true setzen. Dadurch wird verhindert, dass die Anfrage bei einem Fehlschlagen einer Anfrage eine Ausnahme auslöst. Außerdem können Sie den Antwortcode und den Inhalt der Anfrage im zurückgegebenen HttpResponse-Objekt prüfen.

Wenn das Add-on erkennt, dass eine Autorisierung erforderlich ist, sollte es den Autorisierungsvorgang auslösen.

Autorisierungsvorgang aufrufen

Zum Aufrufen des Autorisierungsvorgangs verwenden Sie den Kartendienst, um ein AuthorizationException-Objekt zu erstellen, seine Attribute festzulegen und dann die Funktion throwException() aufzurufen. Bevor Sie die Ausnahme auslösen, geben Sie Folgendes an:

  1. Erforderlich. Eine Autorisierungs-URL. Diese wird vom Nicht-Google-Dienst angegeben und ist der Ort, zu dem der Nutzer zu Beginn des Autorisierungsvorgangs weitergeleitet wird. Sie legen diese URL mit der Funktion setAuthorizationUrl() fest.
  2. Erforderlich. Ein String für den Anzeigenamen der Ressource. Identifiziert die Ressource für den Nutzer, wenn die Autorisierung angefordert wird. Sie legen diesen Namen mit der Funktion setResourceDisplayName() fest.
  3. Der Name einer Callback-Funktion, die eine benutzerdefinierte Autorisierungsaufforderung erstellt. Dieser Callback gibt ein Array von erstellten Card-Objekten zurück, aus denen eine UI für die Autorisierung besteht. Dies ist optional. Wenn Sie nichts festlegen, wird die Standardautorisierungskarte verwendet. Die Callback-Funktion legen Sie mit der Funktion setCustomUiCallback() fest.

Beispiel für eine Nicht-Google-OAuth-Konfiguration

Dieses Codebeispiel zeigt, wie Sie ein Add-on für die Verwendung einer nicht von Google stammenden API konfigurieren, die OAuth erfordert. Dabei wird OAuth2 for Apps Script verwendet, um einen Dienst für den Zugriff auf die API zu erstellen.

/**
 * 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();
}

Benutzerdefinierte Autorisierungsaufforderung erstellen

Autorisierungskarte für Dienste, die nicht von Google stammen

Standardmäßig hat eine Autorisierungsaufforderung kein Branding und verwendet nur den String für den Anzeigenamen, um anzugeben, auf welche Ressource das Add-on zugreifen möchte. Ihr Add-on kann jedoch eine benutzerdefinierte Autorisierungskarte definieren, die demselben Zweck dient und zusätzliche Informationen und Branding enthalten kann.

Sie definieren eine benutzerdefinierte Aufforderung, indem Sie eine benutzerdefinierte UI-Callback-Funktion implementieren, die ein Array von erstellten Card-Objekten zurückgibt. Dieses Array darf nur eine einzelne Karte enthalten. Wenn mehr angegeben werden, werden die zugehörigen Header in einer Liste angezeigt, was die Nutzer verwirren kann.

Die zurückgegebene Karte muss folgende Voraussetzungen erfüllen:

  • Teilen Sie dem Nutzer mit, dass das Add-on um die Berechtigung für den Zugriff auf einen Nicht-Google-Dienst in seinem Namen bittet.
  • Machen Sie deutlich, welche Berechtigungen das Add-on hat, wenn es autorisiert ist.
  • eine Schaltfläche oder ein ähnliches Widget enthalten, über das der Nutzer zur Autorisierungs-URL des Dienstes weitergeleitet wird. Achten Sie darauf, dass die Funktion dieses Widgets für den Nutzer offensichtlich ist.
  • Das obige Widget muss die Einstellung OnClose.RELOAD_ADD_ON im OpenLink-Objekt verwenden, damit das Add-on nach Erhalt der Autorisierung neu geladen wird.
  • Alle Links, die über die Autorisierungsaufforderung geöffnet werden, müssen HTTPS verwenden.

Du leitest den Autorisierungsvorgang zur Verwendung deiner Karte an, indem du die Funktion setCustomUiCallback() für dein AuthorizationException-Objekt aufrufst.

Das folgende Beispiel zeigt eine benutzerdefinierte Callback-Funktion für die Autorisierungsaufforderung:

/**
 * 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();
  }
}

Drittanbieter-Log-ins für alle Google Workspace-Apps verwalten

Eine gängige Anwendung für Google Workspace-Add-ons ist die Bereitstellung einer Schnittstelle für die Interaktion mit einem Drittanbietersystem innerhalb einer Google Workspace-Hostanwendung. Mit der OAuth2-Bibliothek für Apps Script können Sie Verbindungen zu Drittanbieterdiensten erstellen und verwalten.

In Drittanbietersystemen muss sich der Nutzer häufig mit einer Nutzer-ID, einem Passwort oder anderen Anmeldedaten anmelden. Wenn sich ein Nutzer bei Ihrem Drittanbieterdienst anmeldet, während er einen Google Workspace-Host verwendet, dürfen Sie dafür sorgen, dass er sich beim Wechsel zu einem anderen Google Workspace-Host nicht noch einmal anmelden muss. Verwenden Sie entweder Nutzereigenschaften oder ID-Tokens, um wiederholte Anmeldeanfragen zu vermeiden. Diese werden in den folgenden Abschnitten erläutert.

Nutzereigenschaften

Sie können die Anmeldedaten eines Nutzers in den Nutzereigenschaften von Apps Script speichern. Sie können beispielsweise Ihr eigenes JWT aus dem Anmeldedienst erstellen und in einer Nutzereigenschaft aufzeichnen oder den Nutzernamen und das Passwort für den Dienst notieren.

Nutzereigenschaften sind so definiert, dass sie nur für diesen Nutzer im Skript des Add-ons zugänglich sind. Andere Nutzer und Skripts können nicht auf diese Attribute zugreifen. Unter PropertiesService finden Sie weitere Informationen.

ID-Tokens

Sie können ein Google-ID-Token als Anmeldedaten für Ihren Dienst verwenden. Auf diese Weise wird die Einmalanmeldung (SSO) erreicht. Nutzer sind bereits in Google angemeldet, da sie sich in einer Google-Hostanwendung befinden.