اتصال به خدمات غیر Google از افزونه Google Workspace

پروژه افزودنی Google Workspace شما می‌تواند مستقیماً با سرویس‌های داخلی و پیشرفته Apps Script به بسیاری از محصولات Google متصل شود.

همچنین می‌توانید به APIها و سرویس‌های غیر Google دسترسی داشته باشید. اگر سرویس نیازی به مجوز ندارد، معمولاً می‌توانید یک درخواست UrlFetch مناسب ارائه دهید و سپس از افزونه خود بخواهید پاسخ را تفسیر کند.

با این حال، اگر سرویس غیر Google نیاز به مجوز دارد، باید OAuth را برای آن سرویس پیکربندی کنید. با استفاده از کتابخانه OAuth2 for Apps Script ( نسخه OAuth1 نیز وجود دارد) می‌توانید این فرآیند را آسان‌تر کنید.

استفاده از سرویس OAuth

هنگام استفاده از یک شی سرویس OAuth برای اتصال به یک سرویس غیر Google، افزونه Google Workspace شما باید تشخیص دهد که چه زمانی مجوز لازم است و در زمانی که نیاز است، جریان مجوز را فراخوانی کند.

جریان مجوز شامل موارد زیر است:

  1. هشدار دادن به کاربر مبنی بر اینکه احراز هویت مورد نیاز است و ارائه یک پیوند برای شروع فرآیند.
  2. دریافت مجوز از سرویس غیر Google.
  3. برای دسترسی مجدد به منبع محافظت شده، افزونه را به‌روزرسانی می‌کنید.

هنگامی که مجوز غیر Google مورد نیاز است، زیرساخت افزودنی Google Workspace این جزئیات را مدیریت می کند. افزونه شما فقط باید تشخیص دهد که چه زمانی مجوز لازم است و در صورت لزوم جریان مجوز را فراخوانی کند.

تشخیص آن مجوز لازم است

یک درخواست ممکن است مجوز دسترسی به یک منبع محافظت شده را به دلایل مختلف نداشته باشد، مانند:

  • رمز دسترسی هنوز ایجاد نشده یا منقضی شده است.
  • رمز دسترسی منبع درخواستی را پوشش نمی دهد.
  • رمز دسترسی محدوده های مورد نیاز درخواست را پوشش نمی دهد.

کد افزودنی شما باید این موارد را شناسایی کند. تابع OAuth library hasAccess() می تواند به شما بگوید که آیا در حال حاضر به یک سرویس دسترسی دارید یا خیر. همچنین، هنگام استفاده از درخواست‌های UrlFetchApp fetch() ، می‌توانید پارامتر muteHttpExceptions را روی true تنظیم کنید. این مانع از ایجاد یک استثنا در هنگام شکست درخواست می شود و به شما امکان می دهد کد پاسخ درخواست و محتوای موجود در شی HttpResponse برگشتی را بررسی کنید.

وقتی افزونه تشخیص دهد که مجوز لازم است، باید جریان مجوز را راه‌اندازی کند.

فراخوانی جریان مجوز

شما جریان مجوز را با استفاده از سرویس Card برای ایجاد یک شیء AuthorizationException ، تنظیم خصوصیات آن و سپس فراخوانی تابع throwException() فراخوانی می کنید. قبل از پرتاب استثنا، موارد زیر را ارائه می دهید:

  1. ضروری. یک URL مجوز. این توسط سرویس غیر Google مشخص شده است و مکانی است که کاربر هنگام شروع جریان مجوز به آن برده می شود. شما این URL را با استفاده از تابع setAuthorizationUrl() تنظیم می کنید.
  2. ضروری. یک رشته نام نمایش منبع هنگامی که مجوز درخواست می شود، منبع را برای کاربر شناسایی می کند. شما این نام را با استفاده از تابع setResourceDisplayName() تنظیم می کنید.
  3. نام یک تابع پاسخ به تماس که یک درخواست مجوز سفارشی ایجاد می کند. این بازخوانی آرایه‌ای از اشیاء Card ساخته شده را برمی‌گرداند که یک UI برای مدیریت مجوز تشکیل می‌دهند. این اختیاری است. اگر تنظیم نشده باشد از کارت مجوز پیش فرض استفاده می شود. شما تابع callback را با استفاده از تابع setCustomUiCallback() تنظیم می کنید.

نمونه پیکربندی OAuth غیر Google

این نمونه کد نحوه پیکربندی یک افزونه را برای استفاده از API غیر Google که به OAuth نیاز دارد، نشان می‌دهد. از OAuth2 for 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. 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();
}

ایجاد یک درخواست مجوز سفارشی

کارت مجوز خدمات غیر Google

به‌طور پیش‌فرض، یک درخواست مجوز هیچ علامتی ندارد و فقط از رشته نام نمایشی برای نشان دادن منبعی استفاده می‌کند که افزونه تلاش می‌کند به آن دسترسی پیدا کند. با این حال، افزونه شما می‌تواند یک کارت مجوز سفارشی‌شده را تعریف کند که به همان هدف عمل می‌کند و می‌تواند شامل اطلاعات اضافی و نام تجاری باشد.

شما با اجرای یک تابع بازخوانی رابط کاربری سفارشی که آرایه ای از اشیاء Card ساخته شده را برمی گرداند، یک درخواست سفارشی تعریف می کنید. این آرایه باید فقط شامل یک کارت باشد. اگر موارد بیشتری ارائه شود، سرصفحه های آنها در یک لیست نمایش داده می شود که می تواند منجر به تجربه کاربر گیج کننده شود.

کارت برگشتی باید موارد زیر را انجام دهد:

  • برای کاربر روشن کنید که این افزونه از طرف او برای دسترسی به یک سرویس غیر Google اجازه می‌خواهد.
  • مشخص کنید که افزونه در صورت مجوز چه کاری می تواند انجام دهد.
  • حاوی یک دکمه یا ویجت مشابه است که کاربر را به URL مجوز سرویس می برد. مطمئن شوید که عملکرد این ویجت برای کاربر واضح است.
  • ویجت فوق باید از تنظیم OnClose.RELOAD_ADD_ON در شی OpenLink خود استفاده کند تا اطمینان حاصل شود که افزونه پس از دریافت مجوز مجدداً بارگیری می شود.
  • همه پیوندهای باز شده از درخواست مجوز باید از HTTPS استفاده کنند .

شما با فراخوانی تابع setCustomUiCallback() در شیء AuthorizationException ، جریان مجوز را برای استفاده از کارت خود هدایت می کنید.

مثال زیر یک تابع درخواست مجوز سفارشی را نشان می دهد:

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

مدیریت ورودهای شخص ثالث در برنامه‌های Google Workspace

یکی از برنامه های رایج برای افزونه های Google Workspace، ارائه یک رابط برای تعامل با یک سیستم شخص ثالث از داخل یک برنامه میزبان Google Workspace است. کتابخانه OAuth2 برای Apps Script می تواند به شما در ایجاد و مدیریت اتصالات به سرویس های شخص ثالث کمک کند.

سیستم های شخص ثالث اغلب نیاز دارند که کاربر با استفاده از شناسه کاربری، رمز عبور یا سایر اطلاعات کاربری وارد سیستم شود. وقتی کاربر در حالی که از یک میزبان Google Workspace استفاده می‌کند به سیستم شخص ثالث شما وارد می‌شود، باید مطمئن شوید که وقتی به میزبان Google Workspace دیگری می‌رود، دوباره وارد سیستم نمی‌شود. برای جلوگیری از درخواست های مکرر ورود، از ویژگی های کاربر یا نشانه های شناسه استفاده کنید. این موارد در بخش های بعدی توضیح داده شده است.

ویژگی های کاربر

می‌توانید داده‌های ورود به سیستم کاربر را در ویژگی‌های کاربر Apps Script ذخیره کنید. به عنوان مثال، می توانید JWT خود را از سرویس ورود آنها ایجاد کنید و آن را در یک ویژگی کاربر ثبت کنید، یا نام کاربری و رمز عبور سرویس آنها را ثبت کنید.

دامنه ویژگی های کاربر به گونه ای است که فقط توسط آن کاربر در اسکریپت افزونه شما قابل دسترسی است. سایر کاربران و سایر اسکریپت ها نمی توانند به این ویژگی ها دسترسی داشته باشند. برای جزئیات بیشتر به PropertiesService مراجعه کنید.

نشانه های شناسه

می‌توانید از یک رمز Google ID به عنوان اعتبار ورود به سرویس خود استفاده کنید. این راهی برای دستیابی به یک ورود به سیستم است. کاربران قبلاً وارد Google شده اند زیرا در یک برنامه میزبان Google هستند.