

Если ваше дополнение 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 :
Apps Script
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 поддерживает автоматическое повторение предыдущего выполнения, если триггером является «Сообщение» , «Добавлено в пространство » или «Команда приложения» . Для этих триггеров ваше дополнение получает completeRedirectUri в полезной нагрузке события . Для запуска автоматического повтора необходимо закодировать completeRedirectUri в вашем URL-адресе конфигурации. Перенаправление на этот URL-адрес сигнализирует Google Chat о том, что запрос конфигурации был выполнен, и позволяет Google Chat повторить предыдущее выполнение.
Когда пользователь успешно перенаправляется на адрес configCompleteRedirectUrl указанный в исходном сообщении, Google Chat выполняет следующие действия:
- Удаляет подсказку, отображаемую пользователю, инициировавшем операцию.
- Отправляет исходный объект события тому же дополнению во второй раз.
Если вы не укажете completeRedirectUri в URL-адресе конфигурации, пользователь все равно сможет завершить процесс авторизации. Однако Google Chat не будет повторять предыдущее выполнение, и пользователю придется вручную снова вызвать ваше дополнение.
Приведенный ниже пример кода демонстрирует, как приложение чата может запрашивать учетные данные OAuth2 в автономном режиме, сохранять их в базе данных и использовать для выполнения вызовов API с аутентификацией пользователя .
Apps Script
Node.js
Python
Java
Пользовательская авторизационная карта
Чтобы изменить запрос на авторизацию, вы можете создать пользовательскую карточку для процесса входа в систему вашего сервиса.
Если вы публикуете свое дополнение публично, вам необходимо использовать пользовательскую карту авторизации для всех приложений Google Workspace, кроме чата. Чтобы узнать больше о требованиях к публикации в Google Workspace Marketplace, см. раздел «О проверке приложений» .
Возвращаемая карта должна соответствовать следующим требованиям:
- Четко объясните пользователю, что дополнение запрашивает разрешение на доступ к сервису, не принадлежащему Google, от его имени.
- Чётко укажите, какие функции сможет выполнять дополнение при наличии авторизации.
- Добавьте кнопку или аналогичный виджет, который перенаправляет пользователя на URL-адрес авторизации сервиса. Убедитесь, что функция этого виджета очевидна для пользователя.
- Для обеспечения перезагрузки дополнения после получения авторизации указанный выше виджет должен использовать параметр
OnClose.RELOADв своем объектеOpenLink. - Все ссылки, открываемые после запроса авторизации, должны использовать протокол HTTPS .
На следующем изображении показан пример пользовательской карты авторизации для главной страницы дополнения. Карта включает логотип, описание и кнопку входа в систему:


Следующий код демонстрирует, как использовать этот пример пользовательской карточки:
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
Верните следующий 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 Script обновите метод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. Это способ обеспечить единый вход (SSO). Пользователи уже авторизованы в Google, поскольку находятся в приложении, размещенном на платформе Google.
Пример конфигурации OAuth, не относящейся к Google.
Приведенный ниже пример кода Apps Script демонстрирует, как настроить дополнение для использования API, не принадлежащего Google и требующего аутентификации OAuth. В этом примере используется библиотека OAuth2 for Apps Script для создания сервиса доступа к API.
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();
}