Wenn Ihr Google Workspace-Add-on eine Verbindung zu einem Drittanbieterdienst oder einer Drittanbieter-API herstellt, für die eine Autorisierung erforderlich ist, kann das Add-on Nutzer auffordern, sich anzumelden und den Zugriff zu autorisieren.
Auf dieser Seite wird erläutert, wie Sie Nutzer mithilfe eines Autorisierungsvorgangs (z. B. OAuth) authentifizieren. Dazu sind folgende Schritte erforderlich:
- Erkennen, wann eine Autorisierung erforderlich ist.
- Eine Kartenoberfläche zurückgeben, auf der Nutzer aufgefordert werden, sich im Dienst anzumelden.
- Das Add-on aktualisieren, damit Nutzer auf den Dienst oder die geschützte Ressource zugreifen können.
Wenn für Ihr Add-on nur die Nutzeridentität erforderlich ist, können Sie Nutzer direkt mit ihrer Google Workspace-ID oder E‑Mail-Adresse authentifizieren. Informationen zur Verwendung der E‑Mail Adresse für die Authentifizierung finden Sie unter JSON-Anfragen validieren. Wenn Sie Ihr Add-on mit Google Apps Script erstellt haben, können Sie diesen Vorgang vereinfachen, indem Sie die OAuth2-Bibliothek für Google Apps Script verwenden. Es gibt auch eine OAuth1-Version.
Erkennen, dass eine Autorisierung erforderlich ist
Bei der Verwendung Ihres Add-ons sind Nutzer möglicherweise aus verschiedenen Gründen nicht berechtigt, auf eine geschützte Ressource zuzugreifen. Dazu gehören:
- Es wurde noch kein Zugriffstoken für die Verbindung zum Drittanbieterdienst generiert oder es ist abgelaufen.
- Das Zugriffstoken deckt die angeforderte Ressource nicht ab.
- Das Zugriffstoken deckt nicht die erforderlichen Bereiche der Anfrage ab.
Ihr Add-on sollte diese Fälle erkennen, damit sich Nutzer anmelden und auf Ihren Dienst zugreifen können.
Wenn Sie in Apps Script entwickeln, können Sie mit der Funktion hasAccess der OAuth-Bibliothek prüfen, ob Sie Zugriff auf einen Dienst haben.
Alternativ können Sie bei Verwendung von
UrlFetchApp.fetch
-Anfragen den muteHttpExceptions-Parameter auf true setzen. Dadurch wird verhindert, dass bei einem Fehler in der Anfrage eine Ausnahme ausgelöst wird. Sie können den Antwortcode und den Inhalt der Anfrage im zurückgegebenen
HttpResponse-Objekt prüfen.
Nutzer auffordern, sich in Ihrem Dienst anzumelden
Wenn Ihr Add-on erkennt, dass eine Autorisierung erforderlich ist, muss es eine Karten oberfläche zurückgeben, auf der Nutzer aufgefordert werden, sich im Dienst anzumelden. Die Anmeldekarte muss Nutzer weiterleiten, damit sie den Authentifizierungs- und Autorisierungsvorgang des Drittanbieters in Ihrer Infrastruktur abschließen können.
Wenn Sie Ihr Add-on mit HTTP-Endpunkten erstellen, empfehlen wir, die Ziel-App mit der Google-Anmeldung zu schützen und die Nutzer-ID mit dem Identitätstoken abzurufen, das bei der Anmeldung ausgestellt wird. Die Anforderung „sub“ enthält die eindeutige ID des Nutzers und kann mit der ID aus Ihrem Add-on korreliert werden.
Anmeldekarte erstellen und zurückgeben
Für die Anmeldekarte Ihres Dienstes können Sie die grundlegende Autorisierungskarte von Google verwenden oder eine Karte anpassen, um zusätzliche Informationen wie das Logo Ihrer Organisation anzuzeigen. Wenn Sie Ihr Add-on öffentlich veröffentlichen, müssen Sie eine benutzerdefinierte Karte verwenden.
Grundlegende Autorisierungskarte
Die folgende Abbildung zeigt ein Beispiel für die grundlegende Autorisierungskarte von Google:
Wenn Sie Nutzern eine grundlegende Autorisierungskarte präsentieren möchten, müssen Sie das Objekt AuthorizationError zurückgeben. Der folgende Code zeigt ein Beispiel für ein AuthorizationError-Objekt:
Apps Script
CardService.newAuthorizationException()
.setAuthorizationUrl('AUTHORIZATION_URL')
.setResourceDisplayName('RESOURCE_DISPLAY_NAME')
.throwException();JSON
Geben Sie die folgende JSON-Antwort zurück:
{
"basic_authorization_prompt": {
"authorization_url": "AUTHORIZATION_URL",
"resource": "RESOURCE_DISPLAY_NAME"
}
}
Ersetzen Sie Folgendes:
AUTHORIZATION_URL: Die URL für die Webanwendung, die die Autorisierung verarbeitet.RESOURCE_DISPLAY_NAME: Der Anzeigename für die geschützte Ressource oder den geschützten Dienst. Dieser Name wird dem Nutzer in der Autorisierungsaufforderung angezeigt. Wenn IhrRESOURCE_DISPLAY_NAMEbeispielsweiseExample Accountist, wird in der Aufforderung angezeigt: „Über dieses Add-on können zusätzliche Informationen angezeigt werden, allerdings ist dafür die Genehmigung für den Zugriff auf Ihr Beispielkonto erforderlich.“
Nach Abschluss der Autorisierung wird der Nutzer aufgefordert, das Add-on zu aktualisieren, um auf die geschützte Ressource zuzugreifen.
Autorisierungskarten in Google Chat zurückgeben
Wenn Ihr Add-on Google Chat erweitert und der Nutzer es in Google Chat ausführt, kann er den Autorisierungsvorgang ohne manuelle Aktualisierung abschließen. Google Chat unterstützt automatische Wiederholungen der
vorherigen Ausführung, wenn der
Trigger
Nachricht, Zu Gruppenbereich hinzugefügt oder App-Befehl ist. Bei diesen Triggern empfängt Ihr
Add-on completeRedirectUri in der
Ereignisnutzlast.
Sie müssen completeRedirectUri in der Konfigurations-URL codieren, um automatische Wiederholungen auszulösen. Die Weiterleitung zu dieser URL signalisiert Google Chat, dass die Konfigurationsanfrage erfüllt wurde, und ermöglicht Google Chat, die vorherige Ausführung zu wiederholen.
Wenn ein Nutzer erfolgreich zur configCompleteRedirectUrl weitergeleitet wird, die in der ursprünglichen Nachricht angegeben wurde, führt Google Chat die folgenden Schritte aus:
- Die Aufforderung für den initiierenden Nutzer wird gelöscht.
- Das ursprüngliche Ereignisobjekt wird ein zweites Mal an dasselbe Add-on gesendet.
Wenn Sie completeRedirectUri nicht in der Konfigurations-URL codieren, kann der Nutzer den Autorisierungsvorgang trotzdem abschließen. Google Chat wiederholt die vorherige Ausführung jedoch nicht und der Nutzer muss Ihr Add-on noch einmal manuell aufrufen.
Das folgende Codebeispiel zeigt, wie eine Chat-App Offline-OAuth2-Anmeldedaten anfordern, in einer Datenbank speichern und damit API-Aufrufe mit Nutzerauthentifizierung ausführen kann.
Apps Script
Node.js
Python
Java
Benutzerdefinierte Autorisierungskarte
Wenn Sie die Autorisierungsaufforderung ändern möchten, können Sie eine benutzerdefinierte Karte für die Anmeldung bei Ihrem Dienst erstellen.
Wenn Sie Ihr Add-on öffentlich veröffentlichen, müssen Sie für alle Google Workspace-Hostanwendungen außer Chat eine benutzerdefinierte Autorisierungskarte verwenden. Weitere Informationen zu den Veröffentlichungsanforderungen für den Google Workspace Marketplace finden Sie unter Informationen zur App-Überprüfung.
Die zurückgegebene Karte muss Folgendes tun:
- Dem Nutzer muss klar sein, dass das Add-on in seinem Namen die Berechtigung für den Zugriff auf einen Nicht-Google-Dienst anfordert.
- Es muss klar sein, was das Add-on tun kann, wenn es autorisiert ist.
- Sie muss eine Schaltfläche oder ein ähnliches Widget enthalten, das den Nutzer zur Autorisierungs-URL des Dienstes weiterleitet. Die Funktion dieses Widgets muss für den Nutzer offensichtlich sein.
- Das vorherige Widget muss in seinem
OpenLink-Objekt die EinstellungOnClose.RELOADverwenden, damit das Add-on neu geladen wird, nachdem die Autorisierung eingegangen ist. - Alle Links, die über die Autorisierungsaufforderung geöffnet werden, müssen HTTPS verwenden.
Die folgende Abbildung zeigt ein Beispiel für eine benutzerdefinierte Autorisierungskarte für die Startseite eines Add-ons. Die Karte enthält ein Logo, eine Beschreibung und eine Anmeldeschaltfläche:
Der folgende Code zeigt, wie Sie dieses Beispiel für eine benutzerdefinierte Karte verwenden:
Apps Script
function customAuthorizationCard() {
let cardSection1Image1 = CardService.newImage()
.setImageUrl('LOGO_URL')
.setAltText('LOGO_ALT_TEXT');
let cardSection1Divider1 = CardService.newDivider();
let cardSection1TextParagraph1 = CardService.newTextParagraph()
.setText('DESCRIPTION');
let cardSection1ButtonList1Button1 = CardService.newTextButton()
.setText('Sign in')
.setBackgroundColor('#0055ff')
.setTextButtonStyle(CardService.TextButtonStyle.FILLED)
.setAuthorizationAction(CardService.newAuthorizationAction()
.setAuthorizationUrl('AUTHORIZATION_URL'));
let cardSection1ButtonList1 = CardService.newButtonSet()
.addButton(cardSection1ButtonList1Button1);
let cardSection1TextParagraph2 = CardService.newTextParagraph()
.setText('TEXT_SIGN_UP');
let cardSection1 = CardService.newCardSection()
.addWidget(cardSection1Image1)
.addWidget(cardSection1Divider1)
.addWidget(cardSection1TextParagraph1)
.addWidget(cardSection1ButtonList1)
.addWidget(cardSection1TextParagraph2);
let card = CardService.newCardBuilder()
.addSection(cardSection1)
.build();
return [card];
}
function startNonGoogleAuth() {
CardService.newAuthorizationException()
.setAuthorizationUrl('AUTHORIZATION_URL')
.setResourceDisplayName('RESOURCE_DISPLAY_NAME')
.setCustomUiCallback('customAuthorizationCard')
.throwException();
}
JSON
Geben Sie die folgende JSON-Antwort zurück:
{
"custom_authorization_prompt": {
"action": {
"navigations": [
{
"pushCard": {
"sections": [
{
"widgets": [
{
"image": {
"imageUrl": "LOGO_URL",
"altText": "LOGO_ALT_TEXT"
}
},
{
"divider": {}
},
{
"textParagraph": {
"text": "DESCRIPTION"
}
},
{
"buttonList": {
"buttons": [
{
"text": "Sign in",
"onClick": {
"openLink": {
"url": "AUTHORIZATION_URL",
"onClose": "RELOAD",
"openAs": "OVERLAY"
}
},
"color": {
"red": 0,
"green": 0,
"blue": 1,
"alpha": 1,
}
}
]
}
},
{
"textParagraph": {
"text": "TEXT_SIGN_UP"
}
}
]
}
]
}
}
]
}
}
}
Ersetzen Sie Folgendes:
LOGO_URL: Die URL für ein Logo oder Bild. Muss eine öffentliche URL sein.LOGO_ALT_TEXT: Alt-Text für das Logo oder Bild, z. B.Cymbal Labs Logo.DESCRIPTION: Eine Handlungsaufforderung für Nutzer, sich anzumelden, z. B.Sign in to get started.- So aktualisieren Sie die Anmeldeschaltfläche:
AUTHORIZATION_URL: Die URL für die Webanwendung, die die Autorisierung verarbeitet.- Optional: Wenn Sie die Schaltflächenfarbe ändern möchten, aktualisieren Sie die
colorRGBA-Gleitkommawerte des Felds. Aktualisieren Sie für Apps Script diesetBackgroundColorMethode mit Hexadezimalwerten.
TEXT_SIGN_UP: Ein Text, der Nutzer auffordert, ein Konto zu erstellen, wenn sie noch keines haben. Beispiel:New to Cymbal Labs? <a href=\"https://www.example.com/signup\">Sign up</a> here.
Drittanbieteranmeldungen in Google Workspace-Apps verwalten
Eine häufige Anwendung für Google Workspace-Add-ons ist die Bereitstellung einer Schnittstelle für die Interaktion mit einem Drittanbietersystem aus einer Google Workspace Hostanwendung heraus.
Für Drittanbietersysteme ist oft erforderlich, dass sich Nutzer mit einer Nutzer-ID, einem Passwort oder anderen Anmeldedaten anmelden. Wenn sich ein Nutzer bei Ihrem Drittanbieterdienst anmeldet, während er eine Google Workspace-Hostanwendung verwendet, müssen Sie dafür sorgen, dass er sich nicht noch einmal anmelden muss, wenn er zu einer anderen Google Workspace-Hostanwendung wechselt.
Wenn Sie in Apps Script entwickeln, können Sie wiederholte Anmeldeanfragen mit Nutzereigenschaften oder ID-Tokens verhindern. 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 ein eigenes JSON Web Token (JWT) aus dem Anmeldedienst des Nutzers erstellen und in einer Nutzereigenschaft aufzeichnen oder den Nutzernamen und das Passwort für den Dienst aufzeichnen.
Nutzereigenschaften sind so begrenzt, dass sie nur von diesem Nutzer im Skript Ihres Add-ons aufgerufen werden können. Andere Nutzer und andere Skripts können nicht auf diese Eigenschaften zugreifen. Weitere Informationen finden Sie unter
PropertiesService.
ID-Tokens
Sie können ein Google-ID-Token als Anmeldedaten für Ihren Dienst verwenden. So können Sie die Einmalanmeldung (SSO) einrichten. Nutzer sind bereits in Google angemeldet, da sie sich in einer Google-Hostanwendung befinden.
Beispiel für eine Nicht-Google-OAuth-Konfiguration
Das folgende Apps Script-Codebeispiel zeigt, wie Sie ein Add-on so konfigurieren, dass eine Nicht-Google-API verwendet wird, für die OAuth erforderlich ist. In diesem Beispiel wird die OAuth2-Bibliothek für Apps Script verwendet, um einen Dienst für den Zugriff auf die API zu erstellen.
Apps Script
/**
* 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.
*/
function authCallback(callbackRequest) {
var authorized = getOAuthService().handleCallback(callbackRequest);
if (authorized) {
return HtmlService.createHtmlOutput(
'Success!');
} 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();
}