Opis
Cel: ten dokument wyjaśnia, jak używać klasy narzędzi GoogleCredential do autoryzacji OAuth 2.0 w usługach Google. Informacje o oferowanych przez nas ogólnych funkcjach protokołu OAuth 2.0 znajdziesz w artykule o OAuth 2.0 i bibliotece klienta Google OAuth dla języka Java.
Podsumowanie: aby uzyskać dostęp do chronionych danych przechowywanych w usługach Google, użyj protokołu OAuth 2.0 do autoryzacji. Interfejsy API Google obsługują przepływy OAuth 2.0 w różnych typach aplikacji klienckich. We wszystkich tych procesach aplikacja kliencka żąda tokena dostępu, który jest powiązany tylko z Twoją aplikacją kliencką i właścicielem chronionych danych, do których ma dostęp. Token dostępu jest też powiązany z ograniczonym zakresem określającym rodzaj danych, do których aplikacja kliencka ma dostęp (np. „Zarządzanie zadaniami”). Ważnym celem protokołu OAuth 2.0 jest zapewnienie bezpiecznego i wygodnego dostępu do zabezpieczonych danych przy jednoczesnym zminimalizowaniu potencjalnego wpływu kradzieży tokena dostępu.
Pakiety OAuth 2.0 w bibliotece klienta interfejsów API Google dla języka Java są tworzone na podstawie ogólnej biblioteki klienta Google OAuth 2.0 dla języka Java.
Szczegółowe informacje znajdziesz w dokumentacji Javadoc następujących pakietów:
- 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 pod kątem uwierzytelniania i rozliczeń, niezależnie od tego, czy klient jest zainstalowanym aplikacją, aplikacją mobilną, serwerem WWW czy klientem działającym w przeglądarce.
Instrukcje konfigurowania danych logowania znajdziesz w pomocy do Konsoli interfejsów API.
Dane logowania
GoogleCredential
GoogleCredential to bezpieczna wątek klasa pomocnicza dla OAuth 2.0, która umożliwia dostęp do zabezpieczonych zasobów przy użyciu tokena dostępu. Jeśli na przykład masz już token dostępu, możesz wysłać żądanie w ten 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ść w Google App Engine
Te alternatywne dane uwierzytelniające są oparte na interfejsie Java App Identity API w Google App Engine. W odróżnieniu od danych logowania, w przypadku których aplikacja kliencka prosi o dostęp do danych użytkownika, interfejs App Identity API zapewnia dostęp do danych własnych aplikacji klienckiej.
Użyj identyfikatora AppIdentityCredential (z google-api-client-appengine). Te dane logowania są znacznie prostsze, ponieważ Google App Engine zajmuje się wszystkimi szczegółami. Określasz tylko potrzebny zakres protokołu OAuth 2.0.
Przykładowy kod pobrany ze strony 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 ma zwykle datę ważności po 1 godzinie. Jeśli spróbujesz go użyć, pojawi się błąd.
GoogleCredential automatycznie „odświeża” token, co oznacza po prostu uzyskanie nowego tokena dostępu. Odbywa się to za pomocą długoterminowego tokena odświeżania, który zwykle jest odbierany wraz z tokenem dostępu, jeśli podczas przepływu kodu autoryzacji używasz parametru access_type=offline
(patrz GoogleAuthorizationCodeFlow.Builder.setAccessType(String)).
Większość aplikacji musi utrzymywać token dostępu lub token odświeżania danych logowania. Aby zachować tokeny dostępu lub odświeżania danych logowania, możesz udostępnić własną implementację DataStoreFactory za pomocą StoredCredential lub użyć jednej z tych implementacji udostępnianych przez bibliotekę:
- AppEngineDataStoreFactory: zachowuje dane logowania przy użyciu interfejsu Google App Engine Data Store API.
- MemoryDataStoreFactory: „zachowuje” dane logowania w pamięci, co jest przydatne tylko jako pamięć krótkoterminowa przez cały okres trwania procesu.
- FileDataStoreFactory: zachowuje dane logowania w pliku.
Użytkownicy AppEngine: interfejs AppEngineCredentialStore został wycofany i wkrótce zostanie usunięty. Zalecamy korzystanie z AppEngineDataStoreFactory ze StoredCredential. Jeśli masz dane logowania zapisane w starym stylu, możesz przeprowadzić migrację za pomocą dodanych metod pomocniczych migrateTo(AppEngineDataStoreFactory) lub migrateTo(DataStore).
Możesz użyć funkcji DataStoreCredentialRefreshListener i ustawić ją na potrzeby danych logowania za pomocą funkcji GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener).
Przepływ kodu autoryzacji
Użyj przepływu kodu autoryzacji, aby umożliwić użytkownikowi przyznanie aplikacji dostępu do swoich chronionych danych w interfejsach API Google. Protokół tego procesu jest określony w sekcji Przyznawanie kodu autoryzacji.
Ten proces jest zaimplementowany za pomocą metody GoogleAuthorizationCodeFlow. Kroki:
- Użytkownik loguje się w Twojej aplikacji. Musisz powiązać go z identyfikatorem, który jest unikalny dla Twojej aplikacji.
- Wywołaj metodę AuthorizationCodeFlow.loadCredential(String)) na podstawie identyfikatora użytkownika, aby sprawdzić, czy są już one znane. Jeśli tak, to już wszystko.
- Jeśli nie, wywołaj AuthorizationCodeFlow.newAuthorizationUrl() i przekieruj przeglądarkę użytkownika na stronę autoryzacji, aby przyznać aplikacji dostęp do swoich chronionych danych.
- Serwer autoryzacji Google przekieruje 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ą AuthorizationCodeFlow.newTokenRequest(String)). - Użyj funkcji AuthorizationCodeFlow.createAndStoreCredential(TokenResponse, String)), aby przechowywać i uzyskiwać dane logowania umożliwiające dostęp do zabezpieczonych zasobów.
Jeśli nie używasz GoogleAuthorizationCodeFlow, możesz też użyć klas niższego poziomu:
- Użyj metody 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 metody AuthorizationCodeResponseUrl, aby przetworzyć odpowiedź autoryzacji i przeanalizować kod autoryzacji.
- Użyj GoogleAuthorizationCodeTokenRequest, aby zażądać tokena dostępu i ewentualnie tokena odświeżania.
- Utwórz nowy parametr GoogleCredential i przechowuj go za pomocą DataStore.set(String, V).
- Uzyskaj dostęp do zabezpieczonych zasobów za pomocą
GoogleCredential
. Wygasłe tokeny dostępu będą automatycznie odświeżane za pomocą tokena odświeżania (w stosownych przypadkach). Pamiętaj, aby użyć funkcji DataStoreCredentialRefreshListener. Ustaw ją na potrzeby danych logowania za pomocą funkcji GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
Podczas konfigurowania projektu w Konsoli interfejsów API Google wybierasz różne dane logowania w zależności od używanego procesu. Więcej informacji znajdziesz w artykułach o konfigurowaniu OAuth 2.0 i Scenariuszach OAuth 2.0. Poniżej znajdziesz fragmenty kodu z każdego procesu.
Aplikacje serwera WWW
Protokół tego procesu został opisany w sekcji Używanie OAuth 2.0 w aplikacjach serwerowych.
Ta biblioteka udostępnia klasy pomocnicze serwletu, które znacznie upraszczają przepływ kodu autoryzacji w podstawowych przypadkach użycia. Wystarczy, że podasz konkretne podklasy AbstractAuthorizationCodeServlet i AbstractAuthorizationCodeCallbackServlet (z google-oauth-client-servlet) oraz dodasz je do pliku web.xml. Pamiętaj, że nadal musisz się zalogować do 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 przepływ kodu autoryzacji serwletu z wyjątkiem interfejsu API Java użytkownika Google App Engine. Aby można było włączyć interfejs User Java API, użytkownik musi być zalogowany. Informacje o przekierowywaniu użytkowników na stronę logowania, jeśli nie są jeszcze zalogowani, znajdziesz w artykule Zabezpieczenia i uwierzytelnianie (w pliku web.xml).
Główna różnica względem przypadku serwletu polega na tym, że udostępniasz konkretne podklasy AbstractAppEngineAuthorizationCodeServlet i AbstractAppEngineAuthorizationCodeCallbackServlet (z google-oauth-client-appengine).
Rozszerzają one abstrakcyjne klasy serwletu i implementują metodę getUserId
za pomocą interfejsu User Java API. AppEngineDataStoreFactory (z google-http-client-appengine) to dobra opcja przechowywania danych logowania przy użyciu interfejsu Google App Engine Data Store API.
Przykład pobrany (trochę zmodyfikowany) na podstawie atrybutu 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(); } }
Dodatkowy przykład znajdziesz w artykule storage-serviceaccount-appengine-sample.
Konta usługi
GoogleCredential obsługuje też konta usługi. W odróżnieniu od danych logowania, w których aplikacja kliencka prosi o dostęp do danych użytkownika, konta usługi zapewniają dostęp do danych własnych aplikacji klienckiej. Aplikacja kliencka podpisuje żądanie tokena dostępu za pomocą klucza prywatnego pobranego z Konsoli interfejsów API Google.
Przykładowy kod pobrany z pliku 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(); ...
Dodatkowy przykład znajdziesz w artykule storage-serviceaccount-cmdline-sample.
Podszywanie się pod inne osoby
Możesz też użyć procedury konta usługi, aby podszywać się pod użytkownika w swojej domenie. Ten proces jest bardzo podobny do opisanego powyżej procesu dotyczącego konta usługi, z tym że dodatkowo wywołujesz funkcję GoogleCredential.Builder.setServiceAccountUser(String).
Zainstalowane aplikacje
Jest to przepływ kodu autoryzacji wiersza poleceń opisany w artykule Korzystanie z protokołu OAuth 2.0 w zainstalowanych aplikacjach.
Przykładowy fragment kodu z 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 procedury klienckiej w przeglądarce opisanej w artykule Korzystanie z protokołu OAuth 2.0 w aplikacjach po stronie klienta, zwykle wykonuje się te czynności:
- Przekieruj użytkownika w przeglądarce na stronę autoryzacji za pomocą metody GoogleBrowserClientRequestUrl, aby przyznać przeglądarce dostęp do chronionych danych użytkownika.
- Aby przetworzyć token dostępu znajdujący się we fragmencie adresu URL w identyfikatorze URI przekierowania zarejestrowanym w Konsoli interfejsów API Google, użyj biblioteki klienta interfejsu API Google dla JavaScript.
Przykładowe zastosowanie 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órej biblioteki używać na Androidzie:
Jeśli tworzysz na Androida, a interfejs API Google, którego chcesz używać, jest dostępny w bibliotece Usług Google Play, korzystaj z niej, aby uzyskać najwyższą wydajność i wygodę użytkowania. Jeśli interfejs Google API, którego chcesz używać z Androidem, nie jest częścią biblioteki Usług Google Play, możesz użyć biblioteki klienta interfejsów API Google dla Javy, która obsługuje Androida w wersji 4.0 (Ice Cream Sandwich) (lub nowszej) i opisaną tutaj. Biblioteka klienta interfejsów API Google dla języka Java w przypadku Androida jest obsługiwana przez @Beta.
Informacje ogólne:
Od wersji Eclair (SDK 2.1) konta użytkowników są zarządzane na urządzeniach z Androidem za pomocą Menedżera konta. Całą autoryzacją aplikacji na Androida zarządza się centralnie przez pakiet SDK za pomocą funkcji AccountManager. Określasz zakres OAuth 2.0, którego potrzebuje aplikacja, a aplikacja zwraca token dostępu, którego ma używać.
Zakres protokołu OAuth 2.0 jest określany w parametrze authTokenType
jako oauth2:
plus zakres. Na przykład:
oauth2:https://www.googleapis.com/auth/tasks
Określa uprawnienia do zapisu i odczytu w interfejsie Google Tasks API. Jeśli potrzebujesz wielu zakresów OAuth 2.0, użyj listy rozdzielonej spacjami.
Niektóre interfejsy API mają specjalne parametry authTokenType
, które również działają. Na przykład „Zarządzanie zadaniami” jest aliasem przykładu authtokenType
pokazanego powyżej.
Musisz też podać klucz interfejsu API w Konsoli interfejsów API Google. W przeciwnym razie token otrzymany od menedżera konta zapewnia Ci tylko limit anonimowy, który zwykle jest bardzo niski. Jeśli z kolei podasz klucz interfejsu API, uzyskasz wyższy bezpłatny limit. Możesz wtedy skonfigurować płatności za wykorzystanie powyżej tego limitu.
Przykładowy fragment kodu pobrany z aplikacji 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; } }