Sunucu tarafı uygulamalar için Google ile Oturum Açma

Kullanıcı çevrimdışıyken bir kullanıcı adına Google hizmetlerini kullanmak için karma bir sunucu tarafı akış kullanmanız gerekir. Bu akış, kullanıcının JavaScript API istemcisini kullanarak istemci tarafında uygulamanızı yetkilendirdiği ve sunucunuza özel tek seferlik yetkilendirme kodu gönderdiğiniz durumlardır. Sunucunuz, kendi API çağrılarını elde etmek ve sunucunun kendi API çağrılarını yapabilmesi için Google'dan jetonları yenilemek amacıyla bu tek kullanımlık kodu değiştirir. Bu işlem, kullanıcı çevrimdışıyken yapılabilir. Bu tek seferlik kod akışının, hem sunucu tarafı akışa hem de sunucunuza erişim jetonları göndermeye göre güvenlik avantajları vardır.

Sunucu tarafı uygulamanız için erişim jetonu almaya yönelik oturum açma akışı aşağıda gösterilmiştir.

Tek kullanımlık kodların çeşitli güvenlik avantajları vardır. Google, kodlar sayesinde jetonları herhangi bir aracı olmadan doğrudan sunucunuza sağlar. Kodların sızdırılmasını önermesek de, istemci gizli anahtarı olmadan kullanılmaları çok zordur. İstemci sırlarını saklı tutun!

Tek seferlik kod akışını uygulama

Google ile Oturum Açma düğmesi hem erişim jetonu hem de yetkilendirme kodu sağlar. Bu kod, sunucunuzun bir erişim jetonu almak için Google sunucularıyla takas edebileceği tek seferlik bir koddur.

Aşağıdaki örnek kod tek seferlik kod akışının nasıl yapılacağını göstermektedir.

Google ile Oturum Açma özelliğini tek seferlik kod akışıyla doğrulamak için şunları yapmanız gerekir:

1. Adım: İstemci kimliği ve istemci gizli anahtarı oluşturun

İstemci kimliği ve istemci gizli anahtarı oluşturmak için Google API Konsolu projesi oluşturun, OAuth istemci kimliği ayarlayın ve JavaScript kaynaklarınızı kaydedin:

  1. Google API Konsolu'na gidin.

  2. Proje açılır menüsünden mevcut bir projeyi seçin veya Yeni proje oluştur'u seçerek yeni bir proje oluşturun.

  3. "API'ler ve Hizmetler"in altındaki kenar çubuğunda Kimlik bilgileri'ni seçin ve ardından İzin ekranını yapılandır'ı tıklayın.

    Bir e-posta adresi seçin, bir ürün adı belirtin ve Kaydet'e basın.

  4. Credentials (Kimlik bilgileri) sekmesinde, Create credentials (Kimlik bilgileri oluştur) açılır listesini seçip OAuth client ID (OAuth istemci kimliği) seçin.

  5. Uygulama türü bölümünde Web uygulaması'nı seçin.

    Uygulamanızın Google API'lerine erişmesine izin verilen kaynakları aşağıdaki gibi kaydedin. Kaynak; protokol, ana makine adı ve bağlantı noktasının benzersiz bir kombinasyonudur.

    1. Yetkili JavaScript kaynakları alanına uygulamanızın kaynağını girin. Uygulamanızın farklı protokollerde, alanlarda veya alt alanlarda çalışmasına olanak tanımak için birden fazla kaynak girebilirsiniz. Joker karakterler kullanamazsınız. Aşağıdaki örnekte, ikinci URL bir üretim URL'si olabilir.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. Yetkili yönlendirme URI'si alanı bir değer gerektirmez. Yönlendirme URI'leri JavaScript API'leriyle kullanılmaz.

    3. Oluştur düğmesine basın.

  6. Karşınıza çıkan OAuth istemcisi iletişim kutusunda, İstemci Kimliği'ni kopyalayın. İstemci kimliği, uygulamanızın etkin Google API'lerine erişmesine olanak tanır.

2. Adım: Google platform kitaplığını sayfanıza ekleyin

Bu index.html web sayfasının DOM'sine komut dosyası ekleyen anonim bir işlevi gösteren aşağıdaki komut dosyalarını ekleyin.

<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
  <!-- BEGIN Pre-requisites -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
  </script>
  <!-- END Pre-requisites -->

3. Adım: GoogleAuth nesnesini başlatın

auth2 kitaplığını yükleyin ve GoogleAuth nesnesini başlatmak için gapi.auth2.init() çağrısı yapın. init() işlevini çağırırken istemci kimliğinizi ve istekte bulunmak istediğiniz kapsamları belirtin.

<!-- Continuing the <head> section -->
  <script>
    function start() {
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
          // Scopes to request in addition to 'profile' and 'email'
          //scope: 'additional_scope'
        });
      });
    }
  </script>
</head>
<body>
  <!-- ... -->
</body>
</html>

4. Adım: Oturum açma düğmesini sayfanıza ekleyin

Web sayfanıza oturum açma düğmesini ekleyin ve tek seferlik kod akışını başlatmak için bir tıklama işleyici (grantOfflineAccess()) ekleyin.

<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
  $('#signinButton').click(function() {
    // signInCallback defined in step 6.
    auth2.grantOfflineAccess().then(signInCallback);
  });
</script>

5. adım: Kullanıcının oturum açın

Kullanıcı, oturum açma düğmesini tıklar ve uygulamanızın istediğiniz izinlere erişmesine izin verir. Daha sonra, grantOfflineAccess().then() yönteminde belirttiğiniz geri çağırma işlevine yetkilendirme kodu olan bir JSON nesnesi iletilir. Örneğin:

{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}

6. Adım: Yetkilendirme kodunu sunucuya gönderin

code, sunucunuzun kendi erişim jetonu ve yenileme jetonu için değiştirebileceği tek seferlik kodunuzdur. Yenileme jetonu yalnızca kullanıcıya çevrimdışı erişim isteyen bir yetkilendirme iletişim kutusu gösterildikten sonra alabilirsiniz. 4. adımdaki OfflineAccessOptions içinde select-account prompt belirttiyseniz sonraki exchange'ler yenileme jetonu için null değerini döndüreceğinden daha sonra kullanmak üzere aldığınız yenileme jetonunu depolamanız gerekir. Bu akış, standart OAuth 2.0 akışınıza göre daha fazla güvenlik sağlar.

Erişim jetonları her zaman geçerli bir yetkilendirme kodu karşılığında döndürülür.

Aşağıdaki komut dosyası, oturum açma düğmesi için bir geri çağırma işlevi tanımlar. Bir oturum açma işlemi başarılı olduğunda işlev, erişim jetonunu istemci tarafı kullanım için depolar ve tek seferlik kodu aynı alan adındaki sunucunuza gönderir.

<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
  if (authResult['code']) {

    // Hide the sign-in button now that the user is authorized, for example:
    $('#signinButton').attr('style', 'display: none');

    // Send the code to the server
    $.ajax({
      type: 'POST',
      url: 'http://example.com/storeauthcode',
      // Always include an `X-Requested-With` header in every AJAX request,
      // to protect against CSRF attacks.
      headers: {
        'X-Requested-With': 'XMLHttpRequest'
      },
      contentType: 'application/octet-stream; charset=utf-8',
      success: function(result) {
        // Handle or verify the server response.
      },
      processData: false,
      data: authResult['code']
    });
  } else {
    // There was an error.
  }
}
</script>

7. Adım: Erişim jetonu için yetkilendirme kodunu değiştirin

Sunucuda, erişim ve yenileme jetonları için yetkilendirme kodunu değiştirin. Kullanıcı adına Google API'lerini çağırmak için erişim jetonunu kullanın ve isteğe bağlı olarak, erişim jetonunun süresi dolduğunda yeni bir erişim jetonu almak için yenileme jetonunu depolayın.

Profil erişimi isteğinde bulunduysanız kullanıcının temel profil bilgilerini içeren bir kimlik jetonu da alırsınız.

Örneğin:

Java
// (Receive authCode via HTTPS POST)


if (request.getHeader("X-Requested-With") == null) {
  // Without the `X-Requested-With` header, this request could be forged. Aborts.
}

// Set path to the Web application client_secret_*.json file you downloaded from the
// Google API Console: https://console.cloud.google.com/apis/credentials
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "/path/to/client_secret.json";

// Exchange auth code for access token
GoogleClientSecrets clientSecrets =
    GoogleClientSecrets.load(
        JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE));
GoogleTokenResponse tokenResponse =
          new GoogleAuthorizationCodeTokenRequest(
              new NetHttpTransport(),
              JacksonFactory.getDefaultInstance(),
              "https://oauth2.googleapis.com/token",
              clientSecrets.getDetails().getClientId(),
              clientSecrets.getDetails().getClientSecret(),
              authCode,
              REDIRECT_URI)  // Specify the same redirect URI that you use with your web
                             // app. If you don't have a web version of your app, you can
                             // specify an empty string.
              .execute();

String accessToken = tokenResponse.getAccessToken();

// Use access token to call API
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Drive drive =
    new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
        .setApplicationName("Auth Code Exchange Demo")
        .build();
File file = drive.files().get("appfolder").execute();

// Get profile info from ID token
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String userId = payload.getSubject();  // Use this value as a key to identify a user.
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
Python
from apiclient import discovery
import httplib2
from oauth2client import client

# (Receive auth_code by HTTPS POST)


# If this request does not have `X-Requested-With` header, this could be a CSRF
if not request.headers.get('X-Requested-With'):
    abort(403)

# Set path to the Web application client_secret_*.json file you downloaded from the
# Google API Console: https://console.cloud.google.com/apis/credentials
CLIENT_SECRET_FILE = '/path/to/client_secret.json'

# Exchange auth code for access token, refresh token, and ID token
credentials = client.credentials_from_clientsecrets_and_code(
    CLIENT_SECRET_FILE,
    ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
    auth_code)

# Call Google API
http_auth = credentials.authorize(httplib2.Http())
drive_service = discovery.build('drive', 'v3', http=http_auth)
appfolder = drive_service.files().get(fileId='appfolder').execute()

# Get profile info from ID token
userid = credentials.id_token['sub']
email = credentials.id_token['email']