Genel Bakış
Amaç: Bu belgede, Google hizmetleriyle OAuth 2.0 yetkilendirmesi yapmak için GoogleCredential yardımcı 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 için OAuth 2.0 ve Java için Google OAuth İstemci Kitaplığı başlıklı makaleyi inceleyin.
Özet: Google hizmetlerinde depolanan korumalı verilere erişmek için yetkilendirme amacıyla 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şilen korumalı verilerin sahibiyle ilişkilendirilmiş bir erişim jetonu ister. Erişim jetonu, istemci uygulamanızın erişebileceği veri türünü tanımlayan sınırlı bir kapsamla da ilişkilendirilir (örneğin, "Görevlerinizi yönetin"). OAuth 2.0'ın önemli bir hedefi, erişim jetonu çalınması durumunda olası etkiyi en aza indirirken korunan verilere güvenli ve kolay erişim sağlamaktır.
Java için Google API İstemci Kitaplığı'ndaki OAuth 2.0 paketleri, genel amaçlı Java için Google OAuth 2.0 İstemci Kitaplığı üzerine kurulmuştur.
Ayrıntılar için aşağıdaki paketlerin Javadoc belgelerine bakın:
- com.google.api.client.googleapis.auth.oauth2 (google-api-client'tan)
- com.google.api.client.googleapis.extensions.appengine.auth.oauth2 (google-api-client-appengine'den)
Google API Konsolu
Google API'lerine erişebilmeniz için, istemciniz yüklü bir uygulama, mobil uygulama, web sunucusu veya tarayıcıda çalışan bir istemci olsa da kimlik doğrulama ve faturalandırma amacıyla Google API Konsolu'nda bir proje oluşturmanız gerekir.
Kimlik bilgilerinizi doğru şekilde ayarlama talimatları için API Konsolu Yardım Merkezi'ne bakın.
Kimlik bilgisi
GoogleCredential
GoogleCredential, erişim jetonu kullanılarak korunan kaynaklara erişmek için OAuth 2.0'ın iş parçacığı açısından güvenli yardımcı sınıfıdır. Örneğin, zaten bir erişim jetonunuz varsa aşağıdaki şekilde 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'ye dayanır. Bir istemci uygulamasının bir son kullanıcının verilerine erişim isteğinde bulunduğu kimlik bilgilerinin aksine, App Identity API, istemci uygulamasının kendi verilerine erişim sağlar.
AppIdentityCredential'ı kullanın (google-api-client-appengine'den). Google App Engine tüm ayrıntılarla ilgilendiğ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 ardından jetonu kullanmaya çalıştığınızda hata alırsınız.
GoogleCredential, jetonu otomatik olarak "yenileme" işlemini gerçekleştirir. Bu işlem, yeni bir erişim jetonu alma 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 süreli bir yenileme jetonu aracılığıyla yapılır (bkz. GoogleAuthorizationCodeFlow.Builder.setAccessType(String)).
Çoğu uygulamanın kimlik bilgisinin erişim jetonunu ve/veya yenileme jetonunu kalıcı hale getirmesi gerekir. Kimliğin erişim ve/veya yenileme jetonlarını kalıcı hale getirmek için DataStoreFactory'nin kendi uygulamanızı StoredCredential ile sağlayabilir veya kitaplık tarafından sağlanan aşağıdaki uygulamalardan birini kullanabilirsiniz:
- AppEngineDataStoreFactory: Google App Engine Data Store API'yi kullanarak kimlik bilgisini kalıcı hale getirir.
- MemoryDataStoreFactory: Kimliği bellekte "kalıcı hale getirir". Bu yalnızca işlemin ömrü boyunca kısa süreli depolama alanı olarak kullanışlıdır.
- FileDataStoreFactory: Kimlik bilgisini bir dosyada kalıcı hale getirir.
App Engine kullanıcıları: AppEngineCredentialStore desteği sonlandırıldı ve yakında kaldırılacak. StoredCredential ile AppEngineDataStoreFactory'yi kullanmanızı öneririz. Kimlik bilgileriniz eski yöntemle depolanıyorsa geçişi yapmak için eklenen yardımcı yöntemler migrateTo(AppEngineDataStoreFactory) veya migrateTo(DataStore)'u kullanabilirsiniz.
DataStoreCredentialRefreshListener'ı kullanabilir ve GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener) kullanarak kimlik bilgisi için ayarlayabilirsiniz.
Yetkilendirme kodu akışı
Son kullanıcının, uygulamanıza Google API'lerindeki korumalı verilerine erişim izni vermesine olanak tanımak için yetkilendirme kodu akışını kullanın. Bu akışın protokolü, Authorization Code Grant'te (Yetkilendirme Kodu İzni) belirtilir.
Bu akış, GoogleAuthorizationCodeFlow kullanılarak uygulanır. Adımlar aşağıdaki gibidr:
- Son kullanıcı uygulamanıza giriş yapar. Bu kullanıcıyı, uygulamanız için benzersiz olan bir kullanıcı kimliğiyle ilişkilendirmeniz gerekir.
- Son kullanıcının kimlik bilgilerinin zaten bilindiğini kontrol etmek için kullanıcı kimliğine göre AuthorizationCodeFlow.loadCredential(String)) işlevini çağırın. Bu durumda işlem tamamlanır.
- Aksi takdirde, AuthorizationCodeFlow.newAuthorizationUrl() işlevini çağırın ve son kullanıcının tarayıcısını, uygulamanıza korunmuş verilerine erişim izni vereceği bir yetkilendirme sayfasına yönlendirin.
- Ardından Google yetkilendirme sunucusu, tarayıcıyı
codesorgu parametresiyle birlikte uygulamanız tarafından belirtilen yönlendirme URL'sine geri yönlendirir. AuthorizationCodeFlow.newTokenRequest(String)) kullanarak erişim jetonu istemek içincodeparametresini kullanın. - Korunan kaynaklara erişmek için kimlik bilgisi depolamak ve almak üzere AuthorizationCodeFlow.createAndStoreCredential(TokenResponse, String)) yöntemini kullanın.
Alternatif olarak, GoogleAuthorizationCodeFlow kullanmıyorsanız daha düşük düzeydeki sınıfları kullanabilirsiniz:
- Kullanıcı kimliğine göre kimlik bilgilerini mağazadan yüklemek için DataStore.get(String) yöntemini kullanın.
- Tarayıcıyı yetkilendirme sayfasına yönlendirmek için GoogleAuthorizationCodeRequestUrl'yi kullanın.
- Yetkilendirme yanıtını işlemek ve yetkilendirme kodunu ayrıştırmak için AuthorizationCodeResponseUrl'yi kullanın.
- Erişim jetonu ve muhtemelen yenileme jetonu istemek için GoogleAuthorizationCodeTokenRequest'i kullanın.
- Yeni bir GoogleCredential oluşturun ve DataStore.set(String, V) kullanarak depolayın.
GoogleCredentialkullanarak korunan kaynaklara erişin. Süresi dolmuş erişim jetonları, yenileme jetonu kullanılarak otomatik olarak yenilenir (geçerliyse). DataStoreCredentialRefreshListener'ı kullandığınızdan ve GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener) kullanarak kimlik bilgisi için ayarladığınızdan emin olun.
Projenizi Google API Konsolu'nda ayarlarken 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'ı ayarlama ve OAuth 2.0 Senaryoları başlıklı makaleleri inceleyin. Her akışın kod snippet'lerini aşağıda bulabilirsiniz.
Web sunucusu uygulamaları
Bu akışın protokolü Web Sunucusu Uygulamaları için OAuth 2.0'ı Kullanma bölümünde açıklanmaktadır.
Bu kitaplık, temel kullanım alanları için yetkilendirme kodu akışını önemli ölçüde basitleştirmek üzere servlet yardımcı sınıfları sağlar. AbstractAuthorizationCodeServlet ve AbstractAuthorizationCodeCallbackServlet'in (google-oauth-client-servlet'ten) somut alt sınıflarını sağlamanız ve bunları web.xml dosyanıza eklemeniz yeterlidir. Web uygulamanız için kullanıcı girişini yönetmeniz ve kullanıcı kimliği çı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ışı, Google App Engine'in Users Java API'sini kullanabilmemiz dışında servlet yetkilendirme kodu akışıyla neredeyse aynıdır. Users Java API'nin etkinleştirilmesi için kullanıcının giriş yapmış olması gerekir. Kullanıcılar giriş yapmamışsa onları giriş sayfasına yönlendirme hakkında bilgi edinmek için Güvenlik ve Kimlik Doğrulama'ya (web.xml'de) bakın.
Servlet örneğinden temel fark, AbstractAppEngineAuthorizationCodeServlet ve AbstractAppEngineAuthorizationCodeCallbackServlet'in (google-oauth-client-appengine'den) somut alt sınıflarını sağlamanızdır.
Bunlar, soyut servlet sınıflarını genişletir ve Users Java API'sini kullanarak getUserId yöntemini sizin için uygular. AppEngineDataStoreFactory
(google-http-client-appengine'den)
Google App Engine Data Store API'yi kullanarak kimlik bilgilerini kalıcı hale getirmek için iyi bir seçenektir.
calendar-appengine-sample'dan 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 bir örnek için storage-serviceaccount-appengine-sample sayfasına bakın.
Hizmet hesapları
GoogleCredential hizmet hesaplarını da destekler. Bir istemci uygulamasının bir son kullanıcının verilerine erişim isteğinde bulunduğu kimlik bilgilerinin aksine, hizmet hesapları istemci uygulamasının kendi verilerine erişim sağlar. İstemci uygulamanız, Google API Konsolu'ndan indirilen bir özel anahtarı kullanarak erişim jetonu isteğini imzalar.
Örnek Kullanım:
HttpTransport httpTransport = new NetHttpTransport(); 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(); ...
Ek bir örnek için storage-serviceaccount-cmdline-sample sayfasına bakın.
Kimliğe Bürünme
Sahibi olduğunuz bir alandaki 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 ek olarak GoogleCredential.Builder.setServiceAccountUser(String) işlevini çağırırsınız.
Yüklü uygulamalar
Bu, Yüklü Uygulamalar İçin OAuth 2.0 Kullanma bölümünde açıklanan komut satırı yetkilendirme kodu akışıdır.
Örnek kullanım:
public static void main(String[] args) { try { httpTransport = new NetHttpTransport(); 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ı
Using OAuth 2.0 for Client-side Applications (İstemci Tarafı Uygulamaları İçin OAuth 2.0 Kullanma) bölümünde açıklanan tarayıcı tabanlı istemci akışını kullanmak için genellikle şu adımları uygulamanız gerekir:
- Tarayıcı uygulamanıza son kullanıcının korunan verilerine erişim izni vermek için tarayıcıdaki son kullanıcıyı GoogleBrowserClientRequestUrl kullanarak yetkilendirme sayfasına yönlendirin.
- Google API Console'da kaydedilen yönlendirme URI'sindeki URL parçasında bulunan erişim jetonunu işlemek için 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
Android ile hangi kitaplık kullanılabilir?
Android için geliştirme yapıyorsanız ve kullanmak istediğiniz Google API'si Google Play Hizmetleri kitaplığında yer alıyorsa 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 sonraki sürümleri 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 sürümündedir.
Arka plan bilgileri:
Eclair (SDK 2.1) sürümünden itibaren kullanıcı hesapları, Hesap Yöneticisi kullanılarak Android cihazda yönetilir. Tüm Android uygulama 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 bir erişim jetonu döndürülür.
OAuth 2.0 kapsamı, authTokenType parametresi aracılığıyla oauth2: 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'lerde, çalışan özel authTokenType parametreler bulunur. Örneğin, "Görevlerinizi yönetin" ifadesi, authtokenType yukarıda gösterilen örneğin diğer adıdır.
Ayrıca Google API Konsolu'ndaki API anahtarını da belirtmeniz gerekir. Aksi takdirde, AccountManager'ın size verdiği jeton yalnızca anonim kota sağlar ve bu kota genellikle çok düşüktür. Buna karşılık, bir API anahtarı belirterek daha yüksek bir ücretsiz kota elde edersiniz ve isteğe bağlı olarak bu kotanın üzerindeki kullanım için faturalandırma ayarlayabilirsiniz.
tasks-android-sample'dan 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; } }