Przegląd
Cel: w tym dokumencie wyjaśniamy, jak korzystać z klasy narzędzi GoogleCredential do autoryzacji OAuth 2.0 w usługach Google. Informacje o ogólnych funkcjach OAuth 2.0, które udostępniamy, znajdziesz w artykule o OAuth 2.0 i Bibliotece klienta Google OAuth na potrzeby Javy.
Podsumowanie: aby uzyskać dostęp do chronionych danych przechowywanych w usługach Google, użyj OAuth 2.0 do autoryzacji. Interfejsy Google API obsługują przepływy OAuth 2.0 dla różnych typów aplikacji klienckich. We wszystkich tych procesach aplikacja kliencka żąda tokena dostępu powiązanego tylko z aplikacją kliencką i właścicielem chronionych danych. Token dostępu jest też powiązany z ograniczonym zakresem, który określa rodzaj danych, do których aplikacja kliencka ma dostęp (na przykład „"Zarządzaj zadaniami”. Ważnym celem protokołu OAuth 2.0 jest zapewnienie bezpiecznego i wygodnego dostępu do chronionych danych oraz minimalizowanie potencjalnego wpływu, jeśli token dostępu zostanie skradziony.
Pakiety OAuth 2.0 w Bibliotece klienta Google API dla języka Java są oparte na ogólnych zasobach Google OAuth 2.0 dla Javy.
Szczegółowe informacje na temat tych pakietów znajdziesz w dokumentacji Javadoc:
- com.google.api.client.googleapis.auth.oauth2 (z google-api-client)
- com.google.api.client.googleapis.extensions.appengine.auth.oauth2 (z google-api-client-appengine)
Konsola interfejsów API Google
Zanim uzyskasz dostęp do interfejsów API Google, musisz skonfigurować projekt w Konsoli interfejsów API Google na potrzeby uwierzytelniania i rozliczeń. Może to być klient zainstalowany, aplikacja mobilna, serwer WWW lub klient działający w przeglądarce.
Instrukcje dotyczące prawidłowej konfiguracji danych logowania znajdziesz w pomocy konsoli API.
Dane logowania
Dane logowania Google
GoogleCredential to zabezpieczona wątkami klasa pomocnicza protokołu OAuth 2.0, która pozwala uzyskać dostęp do chronionych zasobów za pomocą tokena dostępu. Jeśli na przykład masz już token dostępu, możesz przesłać żądanie w następujący sposób:
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken); Plus plus = new Plus.builder(new NetHttpTransport(), GsonFactory.getDefaultInstance(), credential) .setApplicationName("Google-PlusSample/1.0") .build();
Tożsamość Google App Engine
Alternatywne dane logowania są oparte na interfejsie API Java App Engine App Identity. W przeciwieństwie do danych logowania, w których aplikacja kliencka prosi o dostęp do danych użytkownika, interfejs API tożsamości aplikacji zapewnia dostęp do danych własnych aplikacji klienckiej.
Użyj AppIdentityCredential (z google-api-client-appengine). Te dane logowania są znacznie prostsze, ponieważ Google App Engine dba o wszystkie szczegóły. Określisz tylko potrzebny zakres OAuth 2.0.
Przykładowy kod pobrany z pliku urlshortener-robots-appengine-sample:
static Urlshortener newUrlshortener() { AppIdentityCredential credential = new AppIdentityCredential( Collections.singletonList(UrlshortenerScopes.URLSHORTENER)); return new Urlshortener.Builder(new UrlFetchTransport(), GsonFactory.getDefaultInstance(), credential) .build(); }
magazyn danych
Token dostępu jest zwykle wygasany po 1 godzinie, a po jego próbie pojawi się błąd.
GoogleCredential dba o automatyczny &odświeżanie tokena, czyli uzyskanie nowego tokena dostępu. Jest to realizowane za pomocą długotrwałego tokena odświeżania, który zazwyczaj jest odbierany razem z tokenem dostępu, jeśli używasz parametru access_type=offline
podczas procesu kodu autoryzacji (patrz GoogleAuthorizationCodeFlow.Builder.setAccessType(String)).
Większość aplikacji musi zachować token dostępu danych logowania lub token odświeżania. Aby zachować tokeny dostępu lub tokeny odświeżania, możesz udostępnić własną implementację DataStoreFactory za pomocą StoredCredential. Możesz też użyć jednej z tych implementacji dostępnych w bibliotece:
- AppEngineDataStoreFactory: zachowuje dane logowania za pomocą interfejsu Google App Engine Data Store API.
- MemoryDataStoreFactory: "persists" dane logowania w pamięci, co jest przydatne tylko jako krótkoterminowa pamięć przez cały okres procesu.
- FileDataStoreFactory: przechowuje dane logowania w pliku.
Użytkownicy AppEngine: platforma AppEngineCredentialStore została wycofana i wkrótce zostanie usunięta. Zalecamy użycie AppEngineDataStoreFactory z StoredCredentials. Jeśli masz dane logowania zapisane w starej wersji, możesz użyć dodanych metod pomocniczych migrateTo(AppEngineDataStoreFactory) lub migrateTo(DataStore), aby przeprowadzić migrację.
Możesz użyć DataStoreCredentialRefreshListener i ustawić je dla danych logowania za pomocą GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
Przepływ kodu autoryzacji
Użyj kodu autoryzacji, aby zezwolić użytkownikowi na przyznanie aplikacji dostępu do chronionych danych za pomocą interfejsów API Google. Protokół tego procesu jest określony w grantie kodu autoryzacji.
Ten proces jest zaimplementowany za pomocą GoogleAuthorizationCodeFlow. Kroki:
- Użytkownik loguje się do aplikacji. Musisz powiązać go z identyfikatorem użytkownika, który jest unikalny dla Twojej aplikacji.
- Wywołaj AuthorizationCodeFlow.loadCredential(String)) na podstawie identyfikatora użytkownika, by sprawdzić, czy dane logowania użytkownika są już znane. Jeśli tak, wszystko gotowe.
- Jeśli nie, wywołaj metodę AuthorizationCodeFlow.newAuthorizationUrl() i skieruj przeglądarkę użytkownika na stronę autoryzacji, aby przyznać aplikacji dostęp do chronionych danych.
- Serwer autoryzacji Google przekieruje wtedy przeglądarkę z powrotem do adresu URL przekierowania określonego przez aplikację wraz z parametrem zapytania
code
. Użyj parametrucode
, aby zażądać tokena dostępu za pomocą funkcji AuthorizationCodeFlow.newTokenRequest(ciąg)). - Użyj metody AuthorizationCodeFlow.createAndStoreCredential(TokenResponse, String)) do przechowywania i uzyskiwania danych logowania do uzyskiwania dostępu do chronionych zasobów.
Jeśli nie korzystasz z GoogleAuthorizationCodeFlow, możesz też użyć klas niższego poziomu:
- Użyj narzędzia DataStore.get(String), aby wczytać dane logowania ze sklepu na podstawie identyfikatora użytkownika.
- Użyj GoogleAuthorizationCodeRequestUrl, aby przekierować przeglądarkę na stronę autoryzacji.
- Użyj AuthorizationCodeResponseUrl, by przetworzyć odpowiedź autoryzacji i przeanalizować kod autoryzacji.
- Skorzystaj z GoogleAuthorizationCodeTokenRequest, aby poprosić o token dostępu, a w razie potrzeby token odświeżania.
- Utwórz nowe dane logowania Google i zapisz je za pomocą ciągu DataStore.set(String, V).
- Uzyskaj dostęp do chronionych zasobów za pomocą
GoogleCredential
. Wygasłe tokeny dostępu zostaną automatycznie odświeżone za pomocą tokena odświeżania (w stosownych przypadkach). Pamiętaj, aby użyć polecenia DataStoreCredentialRefreshListener i ustawić je dla danych logowania za pomocą funkcji GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
Podczas konfigurowania projektu w konsoli interfejsu Google API możesz wybrać różne dane logowania w zależności od używanego przepływu. Więcej szczegółów znajdziesz w sekcjach Konfigurowanie protokołu OAuth 2.0 Scenariusze OAuth 2.0. Poniżej znajdziesz fragmenty kodu każdego procesu.
Aplikacje serwera WWW
Protokół tego przepływu opisaliśmy w sekcji Korzystanie z OAuth 2.0 dla aplikacji serwera WWW.
Ta biblioteka udostępnia klasy pomocnicze serwletu, które znacznie upraszczają kod autoryzacji dla podstawowych przypadków użycia. Wystarczy podać konkretne klasy podrzędne AbstractAuthorizationCodeServlet i AbstractAuthorizationCodeCallbackServlet (z google-oauth-client-servlet) i dodać je do pliku web.xml. Nadal musisz zadbać o logowanie użytkownika aplikacji internetowej i wyodrębnić identyfikator użytkownika.
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 } }
Aplikacje Google App Engine
Przepływ kodu autoryzacji w App Engine jest prawie taki sam jak kod autoryzacji serwletu, z wyjątkiem tego, że możemy użyć interfejsu Java Java App Engine. Aby włączyć interfejs Java Java, użytkownik musi być zalogowany. Informacje o przekierowaniu użytkowników na stronę logowania, jeśli nie są jeszcze zalogowani, znajdziesz w artykule Bezpieczeństwo i uwierzytelnianie (w pliku web.xml).
Główną różnicą od przypadku serwletu jest to, że należy podać konkretne podkategorie AbstractAppEngineAuthorizationCodeServlet i AbstractAppEngineAuthorizationCodeCallbackServlet (z google-oauth-client-appengine).
Rozszerzają zajęcia abstrakcyjne i implementują metodę getUserId
za pomocą interfejsu API Java użytkownika. AppEngineDataStoreFactory (z google-http-client-appengine) to dobry sposób na przechowywanie danych logowania za pomocą interfejsu Google App Engine Data Store API.
Przykład (nieznacznie zmodyfikowany) z pliku calendar-appengine-sample:
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(); } }
Więcej przykładów znajdziesz na stronie storage-serviceaccount-appengine-sample.
Konta usługi
GoogleCredential obsługuje też konta usługi. W przeciwieństwie do danych logowania, w których aplikacja kliencka prosi o dostęp do danych użytkownika końcowego, konta usługi zapewniają dostęp do danych użytkownika aplikacji. Aplikacja kliencka podpisuje żądanie tokena dostępu przy użyciu klucza prywatnego pobranego z Google API Console.
Przykładowy kod pobrany z usługi plus-serviceaccount-cmdline-sample:
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(); ...
Więcej informacji znajdziesz na stronie storage-serviceaccount-cmdline-sample.
Podszywanie się pod inne osoby
Możesz też użyć procedury konta usługi, aby podszywać się pod użytkownika z Twojej domeny. Jest to bardzo podobne do powyższego procesu konta usługi, ale dodatkowo wywołujesz metodę GoogleCredential.Builder.setServiceAccountUser(String).
Zainstalowane aplikacje
Jest to przepływ kodu wiersza poleceń opisany w artykule Korzystanie z OAuth 2.0 w przypadku zainstalowanych aplikacji.
Przykładowy fragment z polecenia plus-cmdline-sample:
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"); }
Aplikacje po stronie klienta
Aby skorzystać z przepływu klienta opartego na przeglądarce, który opisano w sekcji Korzystanie z OAuth 2.0 dla aplikacji po stronie klienta, wykonaj te czynności:
- Przekieruj użytkownika w przeglądarce na stronę autoryzacji przy użyciu GoogleBrowserClientRequestUrl, aby przyznać jej dostęp do chronionych danych użytkownika.
- Użyj Biblioteki klienta Google API dla JavaScriptu, aby przetworzyć token dostępu znaleziony we fragmencie adresu URL w identyfikatorze URI przekierowania zarejestrowanym w Konsoli interfejsów API Google.
Przykład użycia aplikacji internetowej:
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
Która biblioteka powinna być używana na urządzeniu z Androidem:
Gdy tworzysz aplikację na Androida, a interfejs Google API, którego chcesz użyć, jest dołączony do Biblioteki Usług Google Play. Jeśli interfejs API Google, z którego chcesz korzystać w przypadku Androida, nie znajduje się w bibliotece usług Google Play, możesz skorzystać z biblioteki klienta interfejsu API Google dla języka Java, która obsługuje Androida 4.0 (Ice Cream Sandwich) lub nowszego. Obsługa Androida w bibliotece klienta interfejsu API Google dla języka Java to @beta.
Informacje ogólne:
Począwszy od Eclair (SDK 2.1), kontami użytkowników zarządza się na urządzeniu z Androidem za pomocą Menedżera kont. Całą autoryzacją aplikacji na Androida zarządza pakiet SDK za pomocą AccountManager. Gdy ustawisz zakres OAuth 2.0 dla swojej aplikacji, zostanie zwrócony token dostępu do użycia.
Zakres OAuth 2.0 określa się za pomocą parametru authTokenType
, oauth2:
jako zakresu plus. Przykład:
oauth2:https://www.googleapis.com/auth/tasks
Określa uprawnienia do zapisu i odczytu interfejsu Google Tasks API. Jeśli potrzebujesz wielu zakresów OAuth 2.0, użyj listy rozdzielonej spacjami.
Niektóre interfejsy API mają też specjalne parametry authTokenType
, które też działają. Na przykład „"Manage your tasks"” jest aliasem przykładu authtokenType
podanego powyżej.
Musisz także określić klucz interfejsu API w Konsoli interfejsów API Google. W przeciwnym razie token przyznany przez Menedżera konta zapewni Ci tylko anonimowy limit, który zwykle jest bardzo niski. Jeśli natomiast podasz odpowiedni klucz interfejsu API, otrzymasz większy bezpłatny limit i możesz opcjonalnie skonfigurować płatności powyżej.
Przykładowy fragment kodu pobrany z tasks-android-sample:
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; } }