Panoramica
Finalità:questo documento spiega come utilizzare la classe di utilità GoogleCredential per eseguire l'autorizzazione OAuth 2.0 con i servizi Google. Per informazioni sulle funzioni OAuth 2.0 generiche che forniamo, vedi OAuth 2.0 e la libreria client OAuth di Google per Java.
Riepilogo: per accedere ai dati protetti memorizzati sui servizi Google, utilizza il protocollo OAuth 2.0 per l'autorizzazione. Le API di Google supportano i flussi OAuth 2.0 per diversi tipi di applicazioni client. In tutti questi flussi, l'applicazione client richiede un token di accesso che è associato solo all'applicazione client e al proprietario dell'accesso ai dati protetti. Il token di accesso è anche associato a un ambito limitato che definisce il tipo di dati a cui l'applicazione client ha accesso, ad esempio "Gestisci le tue attività". Un obiettivo importante per OAuth 2.0 è fornire un accesso sicuro e comodo ai dati protetti, riducendo al minimo il potenziale impatto in caso di furto di un token di accesso.
I pacchetti OAuth 2.0 nella libreria client delle API di Google per Java sono basati sulla libreria client di OAuth 2.0 per Java per uso generico.
Per i dettagli, consulta la documentazione Javadoc per i seguenti pacchetti:
- com.google.api.client.googleapis.auth.oauth2 (da google-api-client)
- com.google.api.client.googleapis.extensions.appengine.auth.oauth2 (da google-api-client-appengine)
console API di Google
Prima di poter accedere alle API di Google, devi configurare un progetto nella console API di Google per finalità di autenticazione e fatturazione, indipendentemente dal fatto che il tuo client sia un'applicazione installata, un'applicazione per dispositivi mobili, un server web o un client eseguito nel browser.
Per istruzioni sulla configurazione corretta delle credenziali, consulta la Guida di API Console.
Credenziale
GoogleCredential
GoogleCredential è una classe helper sicura per i thread per OAuth 2.0 per l'accesso alle risorse protette utilizzando un token di accesso. Ad esempio, se hai già un token di accesso, puoi presentare una richiesta nel seguente modo:
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken); Plus plus = new Plus.builder(new NetHttpTransport(), GsonFactory.getDefaultInstance(), credential) .setApplicationName("Google-PlusSample/1.0") .build();
Identità Google App Engine
Questa credenziale alternativa si basa sull'API Java di App Engine di Google App Engine. A differenza delle credenziali in cui un'applicazione client richiede l'accesso ai dati di un utente finale, l'API App Identity fornisce l'accesso ai propri dati.
Usa AppIdentityCredential (da google-api-client-appengine). Questa credenziale è molto più semplice perché Google App Engine si occupa di tutti i dettagli. Puoi specificare solo l'ambito OAuth 2.0 necessario.
Esempio di codice estratto da 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(); }
Datastore
In genere, un token di accesso ha una data di scadenza di 1 ora, dopodiché verrà visualizzato un errore se tenti di utilizzarlo.
GoogleCredential
si occupa dell'aggiornamento automatico del token, il che significa semplicemente ottenere un nuovo token di accesso. A tal fine si usa un token di aggiornamento di lunga durata, che in genere viene ricevuto insieme al token di accesso se si utilizza il parametro access_type=offline
durante il flusso del codice di autorizzazione (consulta GooglePermissionCodeFlow.Builder.setAccessType(String)).
La maggior parte delle applicazioni dovrà mantenere il token di accesso delle credenziali e/o il token di aggiornamento. Per rendere persistenti i token di accesso e/o di aggiornamento delle credenziali, puoi fornire la tua implementazione di DataStoreFactory con StoredCredential. In alternativa, puoi utilizzare una delle seguenti implementazioni fornite dalla libreria:
- AppEngineDataStoreFactory: continua a utilizzare le credenziali utilizzando l'API Google App Engine Data Store.
- MemoryDataStoreFactory: "persiste" la credenziale in memoria, che è utile solo come spazio di archiviazione a breve termine per l'intera durata del processo.
- FileDataStoreFactory: persiste le credenziali in un file.
Utenti AppEngine: AppEngineCredentialStore è deprecato e verrà rimosso a breve. Ti consigliamo di utilizzare AppEngineDataStoreFactory con StoredCredential. Se hai credenziali archiviate in base alla modalità precedente, puoi utilizzare i metodi di supporto aggiunti migrateTo(AppEngineDataStoreFactory) o migrateTo(DataStore) per eseguire la migrazione.
Puoi utilizzare DataStoreCredentialRefreshListener e impostarlo per la credenziale utilizzando GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener).
Flusso codice di autorizzazione
Utilizza il flusso del codice di autorizzazione per consentire all'utente finale di concedere alla tua applicazione l'accesso ai suoi dati protetti sulle API di Google. Il protocollo per questo flusso è specificato in Autorizzazione al codice di autorizzazione.
Questo flusso viene implementato utilizzando GooglePermissionCodeFlow. I passaggi sono:
- L'utente finale accede all'applicazione. Dovrai associare l'utente a un ID utente univoco per la tua applicazione.
- Chiama PermissionCodeFlow.loadCredential(String)) in base allo User-ID per verificare se le credenziali dell'utente finale sono già note. In tal caso, abbiamo finito.
- In caso contrario, chiama PermissionCodeFlow.newPermissionUrl() e indirizza il browser dell'utente finale a una pagina di autorizzazione per concedere all'applicazione l'accesso ai dati protetti.
- Il server di autorizzazione di Google reindirizza poi il browser all'URL di reindirizzamento specificato dall'applicazione, insieme a un parametro di ricerca
code
. Utilizza il parametrocode
per richiedere un token di accesso utilizzando AutorizzazioneCodeFlow.newTokenRequest(String). - Utilizza PermissionCodeFlow.createAndStoreCredential(TokenResponse, String)) per archiviare e ottenere una credenziale per accedere alle risorse protette.
In alternativa, se non utilizzi GooglePermissionCodeFlow, puoi utilizzare le classi di livello inferiore:
- Utilizza DataStore.get(String) per caricare la credenziale dall'archivio in base all'ID utente.
- Utilizza GooglePermissionCodeRequestUrl per indirizzare il browser alla pagina di autorizzazione.
- Utilizza ConsentCodeResponseUrl per elaborare la risposta di autorizzazione e analizzare il codice di autorizzazione.
- Utilizza GooglePermissionCodeTokenRequest per richiedere un token di accesso ed eventualmente un token di aggiornamento.
- Crea una nuova credenziale Google e archiviala utilizzando DataStore.set(String, V).
- Accedi alle risorse protette utilizzando
GoogleCredential
. I token di accesso scaduti verranno aggiornati automaticamente utilizzando il token di aggiornamento (se applicabile). Assicurati di utilizzare DataStoreCredentialRefreshListener e di impostarlo per la credenziale utilizzando GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener).
Quando configuri il progetto nella console API di Google, puoi scegliere tra diverse credenziali, a seconda del flusso che stai utilizzando. Per maggiori dettagli, vedi Configurare OAuth 2.0 e Scenari OAuth 2.0. Di seguito sono riportati gli snippet di codice per ogni flusso.
Applicazioni server web
Il protocollo per questo flusso è spiegato in Utilizzo di OAuth 2.0 per applicazioni server web.
Questa libreria fornisce classi di supporto servlet per semplificare notevolmente il flusso del codice di autorizzazione per i casi d'uso di base. Fornisci solo classi secondarie AbstractPermissionCodeServlet e AbstractPermissionCodeCallbackServlet (da google-oauth-client-servlet) e aggiungile al tuo file web.xml. Tieni presente che devi comunque occuparti del login utente per la tua applicazione web ed estrarre un ID utente.
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 } }
Applicazioni Google App Engine
Il flusso del codice di autorizzazione su App Engine è quasi identico a quello del codice di autorizzazione del servlet, tranne per il fatto che possiamo utilizzare l'API Users Java di Google App Engine. L'utente deve aver eseguito l'accesso affinché l'API Java dell'utente sia abilitata; per informazioni sul reindirizzamento degli utenti a una pagina di accesso se non è già eseguito l'accesso, consulta Sicurezza e autenticazione (in web.xml).
La differenza principale rispetto al caso servlet è che fornisci sottoclassi concrete di AbstractAppEnginePermissionCodeServlet e AbstractAppEnginePermissionCodeCallbackServlet (da google-oauth-client-appengine).
estendono le classi di servlet astratti e implementano il metodo getUserId
mediante l'API Java degli utenti. AppEngineDataStoreFactory (da google-http-client-appengine) è una buona opzione per rendere persistenti le credenziali utilizzando l'API Google App Engine Data Store.
Esempio estratto (leggermente modificato) da 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(); } }
Per un esempio aggiuntivo, consulta storage-serviceaccount-appengine-sample.
Account di servizio
GoogleCredential supporta anche gli account di servizio. A differenza delle credenziali in cui un'applicazione client richiede l'accesso ai dati di un utente finale, gli account di servizio forniscono l'accesso ai dati dell'applicazione client. L'applicazione client firma la richiesta di un token di accesso utilizzando una chiave privata scaricata dalla console API di Google.
Esempio di codice estratto da 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(); ...
Per un esempio aggiuntivo, consulta storage-serviceaccount-cmdline-sample.
Furto d'identità
Puoi anche utilizzare il flusso dell'account di servizio per impersonare un utente in un dominio di tua proprietà. È molto simile al flusso dell'account di servizio riportato sopra, ma chiami anche GoogleCredential.Builder.setServiceAccountUser(String).
Applicazioni installate
Si tratta del flusso del codice di autorizzazione della riga di comando descritto in Utilizzo di OAuth 2.0 per le applicazioni installate.
Esempio di snippet da 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"); }
Applicazioni lato client
Per utilizzare il flusso client basato su browser descritto nella sezione Utilizzare OAuth 2.0 per applicazioni lato client, in genere segui questi passaggi:
- Reindirizza l'utente finale del browser alla pagina di autorizzazione utilizzando GoogleBrowserClientRequestUrl per concedere all'applicazione del browser l'accesso ai dati protetti dell'utente finale.
- Utilizza la libreria client dell'API di Google per JavaScript per elaborare il token di accesso trovato nel frammento dell'URL nell'URI di reindirizzamento registrato nella console API di Google.
Esempio di utilizzo per un'applicazione web:
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
Quale raccolta da utilizzare con Android:
Se stai sviluppando per Android e l'API di Google che vuoi utilizzare è inclusa nella libreria di Google Play Services, utilizza tale libreria per prestazioni ed esperienza ottimali. Se l'API di Google che vuoi utilizzare con Android non fa parte della libreria di Google Play Services, puoi utilizzare la libreria client delle API di Google per Java, che supporta Android 4.0 (Ice Cream Sandwich) (o una versione successiva), descritta qui. Il supporto per Android nella libreria client delle API di Google per Java è @beta.
Informazioni di base:
A partire da Eclair (SDK 2.1), gli account utente vengono gestiti su un dispositivo Android utilizzando l'Account Manager. Tutta l'autorizzazione delle applicazioni Android viene gestita centralmente dall'SDK tramite AccountManager. Specifica l'ambito OAuth 2.0 di cui la tua applicazione ha bisogno e restituisce un token di accesso da utilizzare.
L'ambito OAuth 2.0 viene specificato tramite il parametro authTokenType
come oauth2:
più l'ambito. Ad esempio:
oauth2:https://www.googleapis.com/auth/tasks
Specifica l'accesso in lettura/scrittura all'API Google Tasks. Se hai bisogno di più ambiti OAuth 2.0, utilizza un elenco separato da spazi.
Alcune API hanno parametri authTokenType
speciali che funzionano anche. Ad esempio, "Gestisci le tue attività"è un alias dell'esempio authtokenType
mostrato sopra.
Devi anche specificare la chiave API nella console API di Google. In caso contrario, il token che ti fornisce l'account manager ti fornisce solo una quota anonima, che di solito è molto bassa. Se invece specifichi una chiave API, riceverai una quota senza costi più elevata e, se vuoi, potrai configurare la fatturazione per l'utilizzo oltre tale limite.
Esempio di snippet di codice estratto da 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; } }