Google Workspace eklentinizi üçüncü taraf hizmetine bağlama

Bağlantı önizlemesinden alınan ve şirketin logosunu, açıklamasını ve oturum açma düğmesini içeren özel yetkilendirme kartı.

Google Workspace eklentiniz, yetkilendirme gerektiren bir üçüncü taraf hizmetine veya API'ye bağlanırsa kullanıcılardan oturum açmalarını ve erişime yetki vermelerini isteyebilir.

Bu sayfada, kullanıcıların kimlik doğrulamasının nasıl yapılacağı açıklanmaktadır. Bu işlem, aşağıdaki adımları içeren bir yetkilendirme akışı (OAuth gibi) kullanılarak gerçekleştirilir:

  1. Yetkilendirmenin ne zaman gerekli olduğunu algılama
  2. Kullanıcılardan hizmette oturum açmalarını isteyen bir kart arayüzü döndürün.
  3. Kullanıcıların hizmete veya korumalı kaynağa erişebilmesi için eklentiyi yenileyin.

Eklentiniz için yalnızca kullanıcı kimliği gerekiyorsa kullanıcıların Google Workspace kimliklerini veya e-posta adreslerini kullanarak doğrudan kimliklerini doğrulayabilirsiniz. Kimlik doğrulama için e-posta adresini kullanmak istiyorsanız JSON isteklerini doğrulama bölümüne bakın. Eklentinizi Google Apps Komut Dosyası'nı kullanarak oluşturduysanız Google Apps Komut Dosyası için OAuth2 kitaplığını kullanarak bu süreci kolaylaştırabilirsiniz (OAuth1 sürümü de mevcuttur).

Yetkilendirmenin gerekli olduğunu algılama

Kullanıcılar, eklentinizi kullanırken aşağıdakiler gibi çeşitli nedenlerle korunan bir kaynağa erişme yetkisine sahip olmayabilir:

  • Üçüncü taraf hizmetine bağlanmak için erişim jetonu henüz oluşturulmamış veya süresi dolmuş.
  • Erişim jetonu, istenen kaynağı kapsamıyor.
  • Erişim jetonu, isteğin gerekli kapsamlarını kapsamıyor.

Eklentiniz, kullanıcıların oturum açıp hizmetinize erişebilmesi için bu durumları algılamalıdır.

Apps Script'te uygulama geliştiriyorsanız OAuth kitaplığı hasAccess() işlevi, bir hizmete erişiminizin olup olmadığını size söyleyebilir. Alternatif olarak, UrlFetchApp fetch() isteklerini kullanırken muteHttpExceptions parametresini true olarak ayarlayabilirsiniz. Bu, isteğin başarısız olması durumunda istek hariç tutma işleminin yapılmasını önler ve döndürülen HttpResponse nesnesinde istek yanıt kodunu ve içeriğini incelemenize olanak tanır.

Kullanıcılardan hizmetinizde oturum açmalarını isteme

Eklentiniz yetkilendirmenin gerekli olduğunu algıladığında, kullanıcılardan hizmette oturum açmalarını isteyen bir kart arayüzü döndürmelidir. Oturum açma kartı, kullanıcıları altyapınızda üçüncü taraf kimlik doğrulama ve yetkilendirme sürecini tamamlamaya yönlendirmelidir.

Eklentinizi HTTP uç noktalarını kullanarak oluştururken hedef uygulamayı Google ile oturum açma ile korumanızı ve oturum açma sırasında verilen kimlik jetonunu kullanarak kullanıcı kimliğini almanızı öneririz. Alt hak talebi, kullanıcının benzersiz kimliğini içerir ve eklentinizdeki kimlikle ilişkilendirilebilir.

Kayıt kartı oluşturma ve iade etme

Hizmetinizin oturum açma kartı için Google'ın temel yetkilendirme kartını kullanabilir veya kuruluşunuzun logosu gibi ek bilgileri görüntülemek için bir kartı özelleştirebilirsiniz. Eklentinizi herkese açık olarak yayınlıyorsanız özel kart kullanmanız gerekir.

Temel yetkilendirme kartı

Aşağıdaki resimde Google'ın temel yetkilendirme kartı örneği gösterilmektedir:

Örnek Hesap için temel yetkilendirme istemi. İstemde, eklentinin ek bilgiler göstermek istediği ancak hesaba erişmek için kullanıcının onayına ihtiyaç duyduğu belirtilir.

Aşağıdaki kodda, Google'ın temel yetkilendirme kartının kullanımıyla ilgili bir örnek gösterilmektedir:

Apps Komut Dosyası

CardService.newAuthorizationException()
    .setAuthorizationUrl('AUTHORIZATION_URL')
    .setResourceDisplayName('RESOURCE_DISPLAY_NAME')
    .throwException();

JSON

Aşağıdaki JSON yanıtını döndürün:

{
  "basic_authorization_prompt": {
    "authorization_url": "AUTHORIZATION_URL",
    "resource": "RESOURCE_DISPLAY_NAME"
  }
}

Aşağıdakini değiştirin:

  • AUTHORIZATION_URL: Yetkilendirmeyi yöneten web uygulamasının URL'si.
  • RESOURCE_DISPLAY_NAME: Korunan kaynağın veya hizmetin görünen adı. Bu ad, kullanıcıya yetkilendirme isteminde gösterilir. Örneğin, RESOURCE_DISPLAY_NAME değeriniz Example Account ise istemde "Bu eklenti ek bilgiler göstermek istiyor ancak Örnek Hesabınıza erişmesi için onay gerekiyor." ifadesi yer alır.

Yetkilendirme tamamlandıktan sonra kullanıcıdan, korunan kaynağa erişmek için eklentiyi yenilemesi istenir.

Özel yetkilendirme kartı

Yetkilendirme isteminde değişiklik yapmak için hizmetinizin oturum açma deneyimi için özel bir kart oluşturabilirsiniz.

Eklentinizi herkese açık olarak yayınlıyorsanız özel bir açık provizyon kartı kullanmanız gerekir. Google Workspace Marketplace'te yayınlama şartları hakkında daha fazla bilgi edinmek için Uygulama incelemesi hakkında başlıklı makaleyi inceleyin.

İade edilen kart aşağıdakileri yapmalıdır:

  • Eklentinin, kullanıcı adına Google dışı bir hizmete erişim izni istediğini açıkça belirtin.
  • Yetkilendirilmişse eklentinin neler yapabileceğini açıkça belirtin.
  • Kullanıcıyı hizmetin yetkilendirme URL'sine yönlendiren bir düğme veya benzer bir widget içermelidir. Bu widget'ın işlevinin kullanıcı tarafından anlaşılır olduğundan emin olun.
  • Yukarıdaki widget, yetkilendirme alındıktan sonra eklentinin yeniden yüklenmesini sağlamak için OpenLink nesnesinde OnClose.RELOAD ayarını kullanmalıdır.
  • Yetkilendirme isteminden açılan tüm bağlantılarda HTTPS kullanılmalıdır.

Aşağıdaki resimde, eklentinin ana sayfası için örnek bir özel yetkilendirme kartı gösterilmektedir. Kartta logo, açıklama ve oturum açma düğmesi bulunur:

Cymbal Labs için şirketin logosunu, açıklamasını ve oturum açma düğmesini içeren özel bir yetkilendirme kartı.

Aşağıdaki kodda, bu özel kart örneğinin nasıl kullanılacağı gösterilmektedir:

Apps Komut Dosyası

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

Aşağıdaki JSON yanıtını döndürün:

{
  "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"
                    }
                  }
                ]
              }
            ]
          }
        }
      ]
    }
  }
}

Aşağıdakini değiştirin:

  • LOGO_URL: Bir logonun veya resmin URL'si. Herkese açık bir URL olmalıdır.
  • LOGO_ALT_TEXT: Logo veya resim için alternatif metin (ör. Cymbal Labs Logo).
  • DESCRIPTION: Kullanıcıların oturum açmasını isteyen bir harekete geçirici mesaj (ör. Sign in to get started).
  • Oturum açma düğmesini güncellemek için:
    • AUTHORIZATION_URL: Yetkilendirmeyi yöneten web uygulamasının URL'si.
    • İsteğe bağlı: Düğme rengini değiştirmek için color alanının RGBA kayan nokta değerlerini güncelleyin. Apps Komut Dosyası için setBackgroundColor() yöntemini onaltılık değerler kullanarak güncelleyin.
  • TEXT_SIGN_UP: Hesabı olmayan kullanıcılardan hesap oluşturmalarını isteyen bir metin. Örneğin, New to Cymbal Labs? <a href=\"https://www.example.com/signup\">Sign up</a> here.

Google Workspace uygulamalarında üçüncü taraf girişlerini yönetme

Google Workspace eklentilerinin yaygın kullanım alanlarından biri, Google Workspace ana uygulama içinden üçüncü taraf bir sistemle etkileşim kurmak için bir arayüz sağlamaktır.

Üçüncü taraf sistemler genellikle kullanıcının kullanıcı kimliği, şifre veya başka bir kimlik bilgisi kullanarak oturum açmasını gerektirir. Bir kullanıcı, bir Google Workspace ana makinesini kullanırken üçüncü taraf hizmetinizde oturum açtığında, başka bir Google Workspace ana makinesine geçiş yaptığında tekrar oturum açmak zorunda kalmamalıdır.

Apps Script'te kod yazıyorsanız kullanıcı özellikleri veya kimlik jetonlarıyla tekrarlanan giriş isteklerini önleyebilirsiniz. Bunlar aşağıdaki bölümlerde açıklanmıştır.

Kullanıcı özellikleri

Kullanıcıların oturum açma verilerini Apps Script'in kullanıcı özelliklerinde saklayabilirsiniz. Örneğin, giriş hizmetlerinden kendi JSON Web jetonunuzu (JWT) oluşturup bunu bir kullanıcı özelliğine kaydedebilir veya hizmetin kullanıcı adını ve şifresini kaydedebilirsiniz.

Kullanıcı özellikleri, yalnızca eklentinizin komut dosyasında ilgili kullanıcı tarafından erişilebilir olacak şekilde kapsamlandırılır. Diğer kullanıcılar ve diğer komut dosyaları bu özelliklere erişemez. Daha fazla bilgi için PropertiesService bölümüne bakın.

Kimlik jetonları

Hizmetinizin giriş kimlik bilgisi olarak Google kimlik jetonu kullanabilirsiniz. Bu, tek oturum açma özelliğini kullanmanın bir yoludur. Kullanıcılar, Google ana makine uygulamasında oldukları için Google'a zaten giriş yapmış olur.

Google dışı OAuth yapılandırması örneği

Aşağıdaki Apps Script kod örneğinde, OAuth gerektiren Google dışı bir API'yi kullanacak şekilde eklentinin nasıl yapılandırılacağı gösterilmektedir. Bu örnekte, API'ye erişmek için bir hizmet oluşturmak üzere Apps Script için OAuth2 kitaplığı kullanılmaktadır.

Apps Komut Dosyası

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