Java 2.0'ı Java için Google API İstemci Kitaplığı ile Kullanma

Genel bakış

Amaç: Bu dokümanda, Google hizmetleriyle OAuth 2.0 yetkilendirmesi yapmak için GoogleCredential yardımcı program sınıfının nasıl kullanılacağı açıklanmaktadır. Sağladığımız genel OAuth 2.0 işlevleri hakkında bilgi edinmek için OAuth 2.0 ve Java için Google OAuth İstemci Kitaplığı başlıklı makaleye bakın.

Özet: Google hizmetlerinde depolanan korumalı verilere erişmek için yetkilendirme için OAuth 2.0'ı kullanın. Google API'leri, farklı istemci uygulaması türleri için OAuth 2.0 akışlarını destekler. Bu akışların tümünde, istemci uygulaması yalnızca istemci uygulamanızla ve erişilmekte olan korunan verilerin sahibiyle ilişkili bir erişim jetonu ister. Erişim jetonu, istemci uygulamanızın eriştiği veri türünü tanımlayan sınırlı bir kapsamla da ilişkilendirilir (örneğin, "Görevlerinizi yönetme"). OAuth 2.0 için önemli bir hedef, korunan verilere güvenli ve kolay erişim olanağı sağlamak ve erişim jetonu çalınması halinde olası etkiyi en aza indirmektir.

Java için Google API İstemci Kitaplığı'ndaki OAuth 2.0 paketleri, Java için Google OAuth 2.0 İstemci Kitaplığı genel amaçlı olarak oluşturulur.

Ayrıntılar için aşağıdaki paketlere ilişkin Javadoc dokümanlarına bakın:

Google API Konsolu

Google API'lerine erişebilmek için istemcinizin yüklü uygulama, mobil uygulama, web sunucusu veya tarayıcıda çalışan bir istemci olması fark etmeksizin, kimlik doğrulama ve faturalandırmayla ilgili amaçlarla Google API Konsolu'nda bir proje oluşturmanız gerekir.

Kimlik bilgilerinizi doğru şekilde ayarlama talimatları için API Konsolu Yardımı'na bakın.

Kimlik Bilgisi

GoogleKimlik Bilgisi

GoogleCredential, bir erişim jetonu kullanarak korumalı kaynaklara erişmek için OAuth 2.0'ın iş parçacığı güvenli bir yardımcı sınıfıdır. Örneğin, zaten bir erişim jetonunuz varsa aşağıdaki biçimde bir istekte bulunabilirsiniz:

GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Plus plus = new Plus.builder(new NetHttpTransport(),
                             GsonFactory.getDefaultInstance(),
                             credential)
    .setApplicationName("Google-PlusSample/1.0")
    .build();

Google App Engine kimliği

Bu alternatif kimlik bilgisi, Google App Engine App Identity Java API'sine dayanır. İstemci kimliği, bir son kullanıcının verilerine erişmek için istediği kimlik bilgisinin aksine App Identity API, istemci uygulamasının kendi verilerine erişim sağlar.

AppIdentityCredential kullanın (google-api-client-appengine üzerinden). Tüm ayrıntıları Google App Engine hallettiği için bu kimlik bilgisi çok daha basittir. Yalnızca ihtiyacınız olan OAuth 2.0 kapsamını belirtirsiniz.

urlshortener-robots-appengine-sample adresinden alınan örnek kod:

static Urlshortener newUrlshortener() {
  AppIdentityCredential credential =
      new AppIdentityCredential(
          Collections.singletonList(UrlshortenerScopes.URLSHORTENER));
  return new Urlshortener.Builder(new UrlFetchTransport(),
                                  GsonFactory.getDefaultInstance(),
                                  credential)
      .build();
}

Veri deposu

Erişim jetonunun geçerlilik süresi genellikle 1 saattir. Bu sürenin sonunda kullanmaya çalışırsanız hata alırsınız. GoogleCredential, jetonu otomatik olarak yeniler ("yenileme") işlemini halleder. Bu, yeni bir erişim jetonu almak anlamına gelir. Bu işlem, yetkilendirme kodu akışı sırasında access_type=offline parametresini kullanırsanız genellikle erişim jetonuyla birlikte alınan uzun ömürlü yenileme jetonu ile gerçekleştirilir (GoogleYetkilendirme KoduFlow.Builder.setAccessType(String) sayfasına bakın).

Çoğu uygulamanın, kimlik bilgisinin erişim jetonunu koruması ve/veya jetonu yenilemesi gerekir. Kimlik bilgisinin erişimini sürdürmek ve/veya jetonları yenilemek için DatadFactory ile kendi DataStoreFactory uygulamanızı sağlayabilir veya kitaplık tarafından sağlanan aşağıdaki uygulamalardan birini kullanabilirsiniz:

AppEngine Kullanıcıları: AppEngineCredentialStore kullanımdan kaldırılmıştır ve yakında kaldırılacaktır. AppEngineDataStoreFactory'yi StoredCredential ile birlikte kullanmanızı öneririz. Eski biçimde depolanan kimlik bilgileriniz varsa taşıma işlemini gerçekleştirmek için migrateTo(AppEngineDataStore) veya migrateTo(DataStore) adlı ek yardımcı yöntemlerini kullanabilirsiniz.

DataStoreCredentialRefreshListener'ı kullanabilir ve GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener) aracılığıyla kimlik bilgisi için ayarlayabilirsiniz.

Yetkilendirme kodu akışı

Son kullanıcıların Google API'leriyle korunan verilerine erişebilmesi için uygulamanızı yetkilendirmesine izin vermek üzere yetkilendirme kodu akışını kullanın. Bu akışın protokolü Yetkilendirme Kodu Verme bölümünde belirtilir.

Bu akış, GoogleAuthorizeCodeFlow kullanılarak uygulanır. Adımlar aşağıdaki gibidr:

  • Son kullanıcı, uygulamanıza giriş yapar. Bu kullanıcıyı, uygulamanıza özgü bir kullanıcı kimliğiyle ilişkilendirmeniz gerekir.
  • Son kullanıcının kimlik bilgilerinin zaten bilinip bilinmediğini kontrol etmek için kullanıcı kimliğini temel alan AuthorizeCodeFlow.loadCredential(String) yöntemini çağırın. Cevabınız evetse işimiz bitti.
  • Aksi takdirde, uygulamanızın korunan verilerine erişmesine izin vermek için AuthorizeCodeFlow.newauthUrl() yöntemini çağırın ve son kullanıcının tarayıcısını bir yetkilendirme sayfasına yönlendirin.
  • Google yetkilendirme sunucusu, tarayıcıyı tekrar bir code sorgu parametresiyle birlikte uygulamanız tarafından belirtilen yönlendirme URL'sine yönlendirir. Yetkilendirme KoduFlow.newTokenRequest(String) kullanarak erişim jetonu istemek için code parametresini kullanın.
  • Korunan kaynaklara erişmek amacıyla kimlik bilgisi depolamak ve almak için AuthorizedCodeFlow.createAndStoreCredential(TokenResponse, String) kullanın.

Alternatif olarak, GoogleauthCodeFlow kullanmıyorsanız alt düzey sınıfları kullanabilirsiniz:

Projenizi Google API Konsolu'nda oluşturduğunuzda, kullandığınız akışa bağlı olarak farklı kimlik bilgileri arasından seçim yaparsınız. Daha fazla bilgi için OAuth 2.0 ve OAuth 2.0 Senaryoları kurma konusuna bakın. Her bir akış için kod snippet'leri aşağıda verilmiştir.

Web sunucusu uygulamaları

Bu akışın protokolü Web Sunucusu Uygulamaları için OAuth 2.0'ı Kullanma başlıklı makalede açıklanmıştır.

Bu kitaplık, temel kullanım alanları için yetkilendirme kodu akışını önemli ölçüde basitleştirmek amacıyla servlet yardımcı sınıfları sağlar. Bunun için yalnızca Abstract belirlerCodeServlet ve AbstractAuthenticationCodeCallbackServlet somut alt sınıflarını sağlamanız (google-oauth-client-servlet kaynağından) ve web.xml dosyanıza eklemeniz yeterlidir. Web uygulamanız için kullanıcı girişi yapmanız ve yine de bir User-ID çıkarmanız gerektiğini unutmayın.

public class CalendarServletSample extends AbstractAuthorizationCodeServlet {

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    // do stuff
  }

  @Override
  protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
    GenericUrl url = new GenericUrl(req.getRequestURL().toString());
    url.setRawPath("/oauth2callback");
    return url.build();
  }

  @Override
  protected AuthorizationCodeFlow initializeFlow() throws IOException {
    return new GoogleAuthorizationCodeFlow.Builder(
        new NetHttpTransport(), GsonFactory.getDefaultInstance(),
        "[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
        Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
        DATA_STORE_FACTORY).setAccessType("offline").build();
  }

  @Override
  protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
    // return user ID
  }
}

public class CalendarServletCallbackSample extends AbstractAuthorizationCodeCallbackServlet {

  @Override
  protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
      throws ServletException, IOException {
    resp.sendRedirect("/");
  }

  @Override
  protected void onError(
      HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse)
      throws ServletException, IOException {
    // handle error
  }

  @Override
  protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
    GenericUrl url = new GenericUrl(req.getRequestURL().toString());
    url.setRawPath("/oauth2callback");
    return url.build();
  }

  @Override
  protected AuthorizationCodeFlow initializeFlow() throws IOException {
    return new GoogleAuthorizationCodeFlow.Builder(
        new NetHttpTransport(), GsonFactory.getDefaultInstance()
        "[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
        Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
        DATA_STORE_FACTORY).setAccessType("offline").build();
  }

  @Override
  protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
    // return user ID
  }
}

Google App Engine uygulamaları

App Engine'deki yetkilendirme kodu akışı, servlet yetkilendirme kodu akışıyla neredeyse aynıdır. Bunun nedeni Google App Engine'in Users Java API'sinden yararlanabilmemizdir. Kullanıcıların Java API'sinin etkinleştirilmesi için kullanıcının giriş yapması gerekir. Kullanıcı henüz giriş yapmadıysanız giriş sayfasına yönlendirme hakkında bilgi için Güvenlik ve Kimlik Doğrulama sayfasını (web.xml) inceleyin.

Ranter örneği arasındaki temel fark, AbstractAppEngineAuthenticationCodeServlet ve AbstractAppEngineAuthenticationCodeCallbackServlet somut alt sınıfları sağlamanızdır (google-oauth-client-appengine üzerinden). Soyut servlet sınıflarını genişletir ve Users Java API'yi kullanarak sizin için getUserId yöntemini uygularlar. AppEngineDataStoreFactory (google-http-client-appengine bağlantısından), Google App Engine DataStore API'yi kullanarak kimlik bilgilerini korumak için iyi bir seçenektir.

calendar-appengine-sample öğesinden alınan (biraz değiştirilmiş) örnek:

public class CalendarAppEngineSample extends AbstractAppEngineAuthorizationCodeServlet {

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    // do stuff
  }

  @Override
  protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
    return Utils.getRedirectUri(req);
  }

  @Override
  protected AuthorizationCodeFlow initializeFlow() throws IOException {
    return Utils.newFlow();
  }
}

class Utils {
  static String getRedirectUri(HttpServletRequest req) {
    GenericUrl url = new GenericUrl(req.getRequestURL().toString());
    url.setRawPath("/oauth2callback");
    return url.build();
  }

  static GoogleAuthorizationCodeFlow newFlow() throws IOException {
    return new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
        getClientCredential(), Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
        DATA_STORE_FACTORY).setAccessType("offline").build();
  }
}

public class OAuth2Callback extends AbstractAppEngineAuthorizationCodeCallbackServlet {

  private static final long serialVersionUID = 1L;

  @Override
  protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
      throws ServletException, IOException {
    resp.sendRedirect("/");
  }

  @Override
  protected void onError(
      HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse)
      throws ServletException, IOException {
    String nickname = UserServiceFactory.getUserService().getCurrentUser().getNickname();
    resp.getWriter().print("<h3>" + nickname + ", why don't you want to play with me?</h1>");
    resp.setStatus(200);
    resp.addHeader("Content-Type", "text/html");
  }

  @Override
  protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
    return Utils.getRedirectUri(req);
  }

  @Override
  protected AuthorizationCodeFlow initializeFlow() throws IOException {
    return Utils.newFlow();
  }
}

Ek örnek için storage-serviceaccount-appengine-sample bölümüne bakın.

Hizmet hesapları

GoogleCredential, hizmet hesaplarını da destekler. Hizmet Hesapları, son kullanıcı verilerine erişim isteğinde bulunan kimlik bilgilerinden farklı olarak, Hizmet Hesapları istemci uygulamasının kendi verilerine erişim sağlar. İstemci uygulamanız erişim jetonu isteğini Google API Konsolu'ndan indirilmiş bir özel anahtarı kullanarak imzalar.

plus-serviceaccount-cmdline-sample adresinden alınan örnek kod:

HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = GsonFactory.getDefaultInstance();
...
// Build service account credential.

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(PlusScopes.PLUS_ME));
// Set up global Plus instance.
plus = new Plus.Builder(httpTransport, jsonFactory, credential)
    .setApplicationName(APPLICATION_NAME).build();
...

Daha fazla örnek için storage-serviceaccount-cmdline-sample bölümüne bakın.

Kimliğe bürünme

Sahibi olduğunuz alandaki bir kullanıcının kimliğine bürünmek için hizmet hesabı akışını da kullanabilirsiniz. Bu, yukarıdaki hizmet hesabı akışına çok benzer ancak GoogleCredential.Builder.setServiceAccountUser(String) çağrısını da yaparsınız.

Yüklü uygulamalar

Bu, Yüklü Uygulamalar İçin OAuth 2.0'ı Kullanma başlıklı makalede açıklanan komut satırı yetkilendirme kodu akışıdır.

plus-cmdline-sample örnek snippet'i:

public static void main(String[] args) {
  try {
    httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
    // authorization
    Credential credential = authorize();
    // set up global Plus instance
    plus = new Plus.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName(
        APPLICATION_NAME).build();
   // ...
}

private static Credential authorize() throws Exception {
  // load client secrets
  GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
      new InputStreamReader(PlusSample.class.getResourceAsStream("/client_secrets.json")));
  // set up authorization code flow
  GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
      httpTransport, JSON_FACTORY, clientSecrets,
      Collections.singleton(PlusScopes.PLUS_ME)).setDataStoreFactory(
      dataStoreFactory).build();
  // authorize
  return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}

İstemci tarafı uygulamalar

İstemci Tarafı Uygulamalar için OAuth 2.0'ı kullanma bölümünde açıklanan tarayıcı tabanlı istemci akışını kullanmak için genellikle aşağıdaki adımları uygularsınız:

  1. Tarayıcı uygulamanıza, son kullanıcının korunan verilerine erişme izni vermek için GoogleBrowserClientRequestUrl öğesini kullanarak tarayıcıdaki son kullanıcıyı yetkilendirme sayfasına yönlendirin.
  2. Google API Konsolu'nda kayıtlı yönlendirme URI'sindeki URL parçasında bulunan erişim jetonunu işlemek üzere JavaScript için Google API İstemci Kitaplığı'nı kullanın.

Web uygulaması için örnek kullanım:

public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException {
  String url = new GoogleBrowserClientRequestUrl("812741506391.apps.googleusercontent.com",
      "https://oauth2.example.com/oauthcallback", Arrays.asList(
          "https://www.googleapis.com/auth/userinfo.email",
          "https://www.googleapis.com/auth/userinfo.profile")).setState("/profile").build();
  response.sendRedirect(url);
}

Android

@Beta

Android ile hangi kitaplık kullanılır?

Android için geliştiriyorsanız ve kullanmak istediğiniz Google API'yi Google Play Hizmetleri kitaplığına dahil ediyorsanız en iyi performans ve deneyim için bu kitaplığı kullanın. Android ile kullanmak istediğiniz Google API, Google Play Hizmetleri kitaplığının bir parçası değilse Android 4.0 (Ice Cream Sandwich) (veya üzeri) sürümünü destekleyen ve burada açıklanan Java için Google API İstemci Kitaplığı'nı kullanabilirsiniz. Java için Google API İstemci Kitaplığı'nda Android desteği @Beta şeklindedir.

Arka plan bilgileri:

Eclair (SDK 2.1) sürümünden itibaren, kullanıcı hesapları Hesap Yöneticisi kullanılarak Android cihazda yönetilmektedir. Tüm Android uygulaması yetkilendirmesi, AccountManager kullanılarak SDK tarafından merkezi olarak yönetilir. Uygulamanızın ihtiyaç duyduğu OAuth 2.0 kapsamını belirtirsiniz ve kullanılacak erişim jetonu döndürür.

OAuth 2.0 kapsamı, authTokenType parametresi aracılığıyla oauth2: ve kapsam olarak belirtilir. Örneğin:

oauth2:https://www.googleapis.com/auth/tasks

Bu, Google Tasks API'ye okuma/yazma erişimini belirtir. Birden fazla OAuth 2.0 kapsamına ihtiyacınız varsa boşlukla ayrılmış bir liste kullanın.

Bazı API'lerin ayrıca çalışan özel authTokenType parametreleri vardır. Örneğin, "Görevlerinizi yönetin" bağlantısı, yukarıda gösterilen authtokenType örneğinin takma adıdır.

API anahtarını Google API Konsolu'ndan da belirtmeniz gerekir. Aksi takdirde, Hesap Yöneticisinin size gönderdiği jeton size yalnızca çok düşük bir anonim kota sağlar. Buna karşılık, bir API anahtarı belirterek daha yüksek ücretsiz kota kazanırsınız ve isteğe bağlı olarak bunun üzerindeki kullanım için faturalandırma ayarlarını yapabilirsiniz.

tasks-android-sample kaynağından alınan örnek kod snippet'i:

com.google.api.services.tasks.Tasks service;

@Override
public void onCreate(Bundle savedInstanceState) {
  credential =
      GoogleAccountCredential.usingOAuth2(this, Collections.singleton(TasksScopes.TASKS));
  SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
  credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
  service =
      new com.google.api.services.tasks.Tasks.Builder(httpTransport, jsonFactory, credential)
          .setApplicationName("Google-TasksAndroidSample/1.0").build();
}

private void chooseAccount() {
  startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  switch (requestCode) {
    case REQUEST_GOOGLE_PLAY_SERVICES:
      if (resultCode == Activity.RESULT_OK) {
        haveGooglePlayServices();
      } else {
        checkGooglePlayServicesAvailable();
      }
      break;
    case REQUEST_AUTHORIZATION:
      if (resultCode == Activity.RESULT_OK) {
        AsyncLoadTasks.run(this);
      } else {
        chooseAccount();
      }
      break;
    case REQUEST_ACCOUNT_PICKER:
      if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) {
        String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);
        if (accountName != null) {
          credential.setSelectedAccountName(accountName);
          SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
          SharedPreferences.Editor editor = settings.edit();
          editor.putString(PREF_ACCOUNT_NAME, accountName);
          editor.commit();
          AsyncLoadTasks.run(this);
        }
      }
      break;
  }
}