การเชื่อมต่อกับบริการที่ไม่ใช่ของ Google จากส่วนเสริมของ Google Workspace

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

โปรเจ็กต์ส่วนเสริม Google Workspace ส่วนเสริมของคุณเชื่อมต่อผลิตภัณฑ์ต่างๆ ของ Google ได้โดยตรงด้วย Apps Script's ในตัวและ ขั้นสูง

นอกจากนี้ คุณยังเข้าถึง API และบริการที่ไม่ใช่ของ Google ได้อีกด้วย หากบริการไม่จําเป็นต้องให้สิทธิ์ โดยทั่วไปคุณสามารถส่งคําขอ UrlFetch ที่เหมาะสมจากนั้นให้ส่วนเสริมตีความการตอบกลับ

แต่หากบริการที่ไม่ใช่ของ Google ต้องให้สิทธิ์ คุณต้องกําหนดค่า OAuth สําหรับบริการดังกล่าว คุณสามารถทําให้ขั้นตอนนี้ง่ายขึ้นได้โดยใช้ไลบรารี OAuth2 for Apps Script (นอกจากนี้ยังมีเวอร์ชัน OAuth1 ด้วย)

การใช้บริการ OAuth

เมื่อใช้ออบเจ็กต์บริการ OAuth เพื่อเชื่อมต่อกับบริการที่ไม่ใช่ของ Google ส่วนเสริมGoogle Workspace จะต้องตรวจหาเมื่อจําเป็นต้องให้สิทธิ์ และเมื่อจําเป็นต้องใช้ ให้เรียกใช้ขั้นตอนการให้สิทธิ์

กระบวนการให้สิทธิ์ประกอบด้วย

  1. แจ้งเตือนผู้ใช้ว่าต้องมีการตรวจสอบสิทธิ์และระบุลิงก์เพื่อเริ่มกระบวนการ
  2. การขออนุญาตจากบริการที่ไม่ใช่ของ Google
  3. กําลังรีเฟรชส่วนเสริมเพื่อลองเข้าถึงทรัพยากรที่มีการป้องกันอีกครั้ง

เมื่อต้องมีการให้สิทธิ์ที่ไม่ใช่ของ GoogleGoogle Workspace โครงสร้างพื้นฐานส่วนเสริมจะจัดการรายละเอียดเหล่านี้ ส่วนเสริมของคุณจะตรวจหาได้เมื่อจําเป็นต้องใช้การให้สิทธิ์และเรียกใช้ขั้นตอนการให้สิทธิ์เมื่อจําเป็นเท่านั้น

ตรวจพบว่าต้องได้รับสิทธิ์

คําขออาจไม่มีสิทธิ์เข้าถึงทรัพยากรที่มีการป้องกันด้วยเหตุผลหลายประการ เช่น

  • โทเค็นการเข้าถึงยังไม่ได้สร้างหรือหมดอายุ
  • โทเค็นเพื่อการเข้าถึงไม่ครอบคลุมทรัพยากรที่ขอ
  • โทเค็นเพื่อการเข้าถึงไม่ครอบคลุมขอบเขตที่จําเป็นตามคําขอ

โค้ดส่วนเสริมของคุณควรตรวจพบกรณีเหล่านี้ ฟังก์ชัน hasAccess() ของไลบรารี OAuth จะบอกให้คุณทราบหากมีการเข้าถึงบริการอยู่ในขณะนี้ หรืออีกทางหนึ่ง เมื่อใช้คําขอ UrlFetchApp fetch() คุณสามารถตั้งค่าพารามิเตอร์ muteHttpExceptions เป็น true ซึ่งจะป้องกันไม่ให้มีคําขอสร้างข้อยกเว้นคําขอที่ล้มเหลว และช่วยให้คุณตรวจสอบโค้ดและการตอบกลับคําขอในออบเจ็กต์ HttpResponse ที่แสดงผลได้

เมื่อส่วนเสริมตรวจพบว่าต้องมีการให้สิทธิ์ ส่วนเสริมจะเรียกใช้ขั้นตอนการให้สิทธิ์

การเรียกใช้กระบวนการให้สิทธิ์

คุณเรียกใช้ขั้นตอนการให้สิทธิ์ได้โดยใช้บริการการ์ดเพื่อสร้างออบเจ็กต์ AuthorizationException ตั้งค่าคุณสมบัติของออบเจ็กต์ แล้วเรียกใช้ฟังก์ชัน throwException() ก่อนที่จะป้อนข้อยกเว้น คุณต้องระบุข้อมูลต่อไปนี้

  1. ต้องระบุ URL การให้สิทธิ์ เมตริกนี้ระบุโดยบริการที่ไม่ใช่ของ Google และเป็นตําแหน่งที่ผู้ใช้จะไปถึงเมื่อเริ่มต้นขั้นตอนการให้สิทธิ์ คุณตั้งค่า URL นี้โดยใช้ฟังก์ชัน setAuthorizationUrl()
  2. ต้องระบุ สตริงชื่อที่แสดงของทรัพยากร ระบุทรัพยากรนั้นให้ผู้ใช้ทราบเมื่อส่งคําขอการให้สิทธิ์ คุณตั้งชื่อนี้โดยใช้ฟังก์ชัน setResourceDisplayName()
  3. ชื่อของฟังก์ชันเรียกกลับที่สร้างพรอมต์การให้สิทธิ์ที่กําหนดเอง โค้ดเรียกกลับนี้จะแสดงอาร์เรย์ของออบเจ็กต์ Card ที่สร้างจํานวนมากซึ่งเขียน UI สําหรับจัดการการให้สิทธิ์ ขั้นตอนนี้ไม่บังคับ หากไม่ได้ตั้งค่าบัตรการให้สิทธิ์เริ่มต้นไว้ คุณตั้งค่าฟังก์ชันเรียกกลับได้โดยใช้ฟังก์ชัน 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

โดยค่าเริ่มต้น ข้อความแจ้งการให้สิทธิ์จะไม่มีแบรนด์ใดๆ และใช้เฉพาะสตริงชื่อที่แสดงเพื่อระบุทรัพยากรที่ส่วนเสริมพยายามจะเข้าถึง อย่างไรก็ตาม ส่วนเสริมของคุณจะกําหนดการ์ดการให้สิทธิ์ที่กําหนดเองซึ่งมีจุดประสงค์เดียวกัน และใส่ข้อมูลเพิ่มเติมและการสร้างแบรนด์ได้

คุณจะกําหนดข้อความแจ้งที่กําหนดเองได้โดยใช้ฟังก์ชันเรียกกลับของ UI ที่กําหนดเองซึ่งจะแสดงผลอาร์เรย์ของออบเจ็กต์ 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 จะช่วยให้คุณสร้างและจัดการการเชื่อมต่อกับบริการของบุคคลที่สามได้

ระบบของบุคคลที่สามมักกําหนดให้ผู้ใช้ต้องลงชื่อเข้าใช้โดยใช้รหัสผู้ใช้ รหัสผ่าน หรือข้อมูลเข้าสู่ระบบอื่นๆ เมื่อผู้ใช้ลงชื่อเข้าใช้บริการของบุคคลที่สามในขณะที่ใช้ #19 Google Workspace อยู่ คุณต้องตรวจสอบว่าตนไม่ต้องลงชื่อเข้าใช้อีกเมื่อเปลี่ยนไปใช้โฮสต์อื่นGoogle Workspace หากต้องการป้องกันคําขอเข้าสู่ระบบซ้ํา ให้ใช้พร็อพเพอร์ตี้ผู้ใช้หรือโทเค็นรหัส ซึ่งอธิบายอยู่ในส่วนต่อไปนี้

พร็อพเพอร์ตี้ผู้ใช้

คุณสามารถเก็บข้อมูลการลงชื่อเข้าใช้ของผู้ใช้ไว้ในพร็อพเพอร์ตี้ผู้ใช้ของ Apps Script ตัวอย่างเช่น คุณสามารถสร้าง JWT ของคุณเองจากบริการเข้าสู่ระบบของผู้ใช้ และบันทึกไว้ในพร็อพเพอร์ตี้ผู้ใช้ หรือบันทึกชื่อผู้ใช้และรหัสผ่านสําหรับบริการของผู้ใช้

ระบบจะกําหนดขอบเขตพร็อพเพอร์ตี้ผู้ใช้ให้เข้าถึงได้โดยผู้ใช้รายดังกล่าวภายในสคริปต์ส่วนเสริมเท่านั้น ผู้ใช้รายอื่นและสคริปต์อื่นๆ เข้าถึงพร็อพเพอร์ตี้เหล่านี้ไม่ได้ ดูรายละเอียดเพิ่มเติมได้ที่ PropertiesService

โทเค็นรหัส

คุณใช้โทเค็นของ Google ID เป็นข้อมูลเข้าสู่ระบบของบริการได้ นี่เป็นวิธีหนึ่งที่จะทําให้สามารถลงชื่อเพียงครั้งเดียว ผู้ใช้ลงชื่อเข้าสู่ระบบ Google อยู่แล้ว เพราะอยู่ในแอปโฮสต์ของ Google