
Если ваше дополнение Google Workspace подключается к сторонней службе или API, требующему авторизации, дополнение может предложить пользователям войти в систему и разрешить доступ.
На этой странице объясняется, как аутентифицировать пользователей с помощью потока авторизации (например, OAuth), который включает следующие шаги:
- Определите, когда требуется авторизация.
- Верните интерфейс карты, который предлагает пользователям войти в сервис.
- Обновите дополнение, чтобы пользователи могли получить доступ к сервису или защищенному ресурсу.
Если вашему дополнению требуется только идентификация пользователя, вы можете аутентифицировать его напрямую, используя его идентификатор Google Workspace или адрес электронной почты. Чтобы использовать адрес электронной почты для аутентификации, см. раздел «Проверка JSON-запросов» . Если вы создали дополнение с использованием Google Apps Script, вы можете упростить этот процесс, используя библиотеку OAuth2 для Google Apps Script (также существует версия OAuth1 ).
Определить, что требуется авторизация
При использовании вашего дополнения пользователи могут не иметь доступа к защищенному ресурсу по ряду причин, например:
- Токен доступа для подключения к сторонней службе еще не сгенерирован или срок его действия истек.
- Токен доступа не охватывает запрошенный ресурс.
- Токен доступа не охватывает требуемые области запроса.
Ваше дополнение должно обнаруживать такие случаи, чтобы пользователи могли войти в систему и получить доступ к вашему сервису.
Если вы разрабатываете приложение в Apps Script, функция hasAccess()
библиотеки OAuth может определить, есть ли у вас доступ к сервису. Кроме того, при использовании запросов UrlFetchApp fetch()
можно установить параметр muteHttpExceptions
в значение true
. Это предотвращает выдачу исключения при сбое запроса и позволяет проверить код ответа и содержимое возвращаемого объекта HttpResponse
.
Предложите пользователям войти в ваш сервис
Когда ваше дополнение обнаруживает необходимость авторизации, оно должно вернуть интерфейс карты , чтобы предложить пользователям войти в сервис. Карта входа должна перенаправлять пользователей для прохождения процесса сторонней аутентификации и авторизации в вашей инфраструктуре.
При создании надстройки с использованием конечных точек HTTP мы рекомендуем защитить целевое приложение с помощью входа через Google и получить идентификатор пользователя, используя токен, выданный при входе. Подзаявка содержит уникальный идентификатор пользователя и может быть сопоставлена с идентификатором из вашей надстройки.
Создайте и верните карту входа
Для карты входа в ваш сервис вы можете использовать базовую карту авторизации Google или настроить карту для отображения дополнительной информации, например логотипа вашей организации. Если вы публикуете дополнение публично, необходимо использовать пользовательскую карту.
Базовая карта авторизации
На следующем изображении показан пример базовой карты авторизации Google:

Чтобы предложить пользователям базовую карту авторизации, необходимо вернуть объект AuthorizationError
. В следующем коде показан пример объекта AuthorizationError
:
Скрипт приложений
CardService.newAuthorizationException() .setAuthorizationUrl('AUTHORIZATION_URL') .setResourceDisplayName('RESOURCE_DISPLAY_NAME') .throwException();
JSON
Верните следующий ответ JSON:
{
"basic_authorization_prompt": {
"authorization_url": "AUTHORIZATION_URL",
"resource": "RESOURCE_DISPLAY_NAME"
}
}
Заменить следующее:
-
AUTHORIZATION_URL
: URL-адрес веб-приложения, которое обрабатывает авторизацию. -
RESOURCE_DISPLAY_NAME
: Отображаемое имя защищённого ресурса или службы. Это имя отображается пользователю при запросе авторизации. Например, если вашRESOURCE_DISPLAY_NAME
—Example Account
, запрос будет содержать следующее: «Это дополнение хочет отображать дополнительную информацию, но для доступа к вашей Example Account требуется разрешение».
После завершения авторизации пользователю предлагается обновить дополнение для доступа к защищенному ресурсу.
Карточки авторизации возврата в Google Chat
Если ваше дополнение расширяет Google Chat и пользователь запускает его в Google Chat, пользователь может завершить процесс авторизации без ручного обновления. Google Chat поддерживает автоматическое повторение предыдущего выполнения, если триггером является Message , Added to space или App command . Для этих триггеров ваше дополнение получает completeRedirectUri
в полезной нагрузке события . Для запуска автоматического повтора необходимо закодировать completeRedirectUri
в URL-адресе конфигурации. Перенаправление на этот URL-адрес сигнализирует Google Chat о том, что запрос конфигурации выполнен, и позволяет Google Chat повторить предыдущее выполнение.
Когда пользователь успешно перенаправлен на configCompleteRedirectUrl
указанный в исходном сообщении, Google Chat выполняет следующие действия:
- Удаляет подсказку, отображаемую инициирующему пользователю.
- Отправляет исходный объект события в то же дополнение второй раз.
Если вы не добавите completeRedirectUri
в URL-адрес конфигурации, пользователь всё равно сможет завершить процесс авторизации. Однако Google Chat не будет повторять предыдущее выполнение, и пользователю придётся вручную снова вызвать ваше дополнение.
В следующем примере кода показано, как приложение чата может запрашивать автономные учетные данные OAuth2, сохранять их в базе данных и использовать их для выполнения вызовов API с аутентификацией пользователя .
Скрипт приложений
Node.js
Питон
Ява
Пользовательская карта авторизации
Чтобы изменить запрос на авторизацию, вы можете создать специальную карту для процедуры входа в систему вашего сервиса.
Если вы публикуете своё дополнение публично, вам необходимо использовать специальную карту авторизации для всех хост-приложений Google Workspace, за исключением Chat. Подробнее о требованиях к публикации в Google Workspace Marketplace см. в статье «Об обзоре приложений» .
Возвращаемая карта должна иметь следующие характеристики:
- Дайте пользователю понять, что дополнение запрашивает разрешение на доступ к сервису, не принадлежащему Google, от его имени.
- Дайте ясно понять, что может делать надстройка, если она авторизована.
- Содержит кнопку или аналогичный виджет, направляющий пользователя на URL-адрес авторизации сервиса. Убедитесь, что функция этого виджета очевидна для пользователя.
- Указанный выше виджет должен использовать настройку
OnClose.RELOAD
в своем объектеOpenLink
, чтобы гарантировать перезагрузку надстройки после получения авторизации. - Все ссылки, открываемые из запроса на авторизацию, должны использовать HTTPS .
На следующем изображении показан пример пользовательской карты авторизации для домашней страницы дополнения. Карточка включает логотип, описание и кнопку входа:

Следующий код показывает, как использовать этот пример пользовательской карты:
Скрипт приложений
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
Верните следующий ответ JSON:
{
"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"
}
}
]
}
]
}
}
]
}
}
}
Заменить следующее:
-
LOGO_URL
: URL-адрес логотипа или изображения. Должен быть общедоступным URL-адресом. -
LOGO_ALT_TEXT
: Альтернативный текст для логотипа или изображения, например,Cymbal Labs Logo
. -
DESCRIPTION
: Призыв к действию для пользователей войти в систему, например:Sign in to get started
. - Чтобы обновить кнопку входа:
-
AUTHORIZATION_URL
: URL-адрес веб-приложения, которое обрабатывает авторизацию. - Необязательно: чтобы изменить цвет кнопки, обновите значения RGBA с плавающей точкой в поле
color
. Для скрипта Apps обновите методsetBackgroundColor()
используя шестнадцатеричные значения.
-
-
TEXT_SIGN_UP
: Текст, предлагающий пользователям создать учётную запись, если у них её нет. Например,New to Cymbal Labs? <a href=\"https://www.example.com/signup\">Sign up</a> here
».
Управление сторонними учетными записями в приложениях Google Workspace
Одним из распространенных применений дополнений Google Workspace является предоставление интерфейса для взаимодействия со сторонней системой из хост-приложения Google Workspace.
Сторонние системы часто требуют от пользователя входа с использованием идентификатора пользователя, пароля или других учётных данных. Когда пользователь входит в ваш сторонний сервис, используя один хост Google Workspace, вы должны убедиться, что ему не придётся входить в систему повторно при переходе на другой хост Google Workspace.
Если вы разрабатываете приложение с использованием Apps Script, вы можете предотвратить повторные запросы на вход с помощью свойств пользователя или токенов ID. Подробнее об этом в следующих разделах.
Свойства пользователя
Вы можете хранить данные для входа пользователя в свойствах пользователя Apps Script. Например, вы можете создать собственный JSON Web Token (JWT) из сервиса входа и записать его в свойство пользователя или записать имя пользователя и пароль для сервиса.
Область действия пользовательских свойств ограничена таким образом, что они доступны только этому пользователю в скрипте вашего дополнения. Другие пользователи и другие скрипты не имеют доступа к этим свойствам. Подробнее см. в разделе PropertiesService
.
Идентификационные токены
Вы можете использовать токен Google ID в качестве учётной записи для входа в ваш сервис. Это способ реализовать единый вход. Пользователи уже авторизованы в Google, поскольку находятся в хост-приложении Google.
Пример конфигурации OAuth не от Google
В следующем примере кода Apps Script показано, как настроить дополнение для использования API, не принадлежащего Google, требующего OAuth. В этом примере используется библиотека OAuth2 для Apps Script для создания сервиса для доступа к 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.
*/
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();
}