Ringkasan
Tujuan: Dokumen ini menjelaskan cara menggunakan GoogleCredential utilitas untuk melakukan otorisasi OAuth 2.0 dengan layanan Google. Sebagai informasi tentang fungsi OAuth 2.0 generik yang kami sediakan, lihat OAuth 2.0 dan Library Klien Google OAuth untuk Java.
Ringkasan: Untuk mengakses data yang dilindungi yang disimpan di layanan Google, gunakan OAuth 2.0 untuk otorisasi. Google API mendukung alur OAuth 2.0 untuk berbagai jenis aplikasi klien. Di semua alur ini, aplikasi klien meminta token akses yang yang hanya dikaitkan dengan aplikasi klien Anda dan pemilik data yang dilindungi sedang diakses. Token akses juga dikaitkan dengan cakupan terbatas yang menentukan jenis data yang dapat diakses oleh aplikasi klien Anda (misalnya "Kelola tugas Anda"). Tujuan penting untuk OAuth 2.0 adalah memberikan keamanan dan akses yang mudah ke data yang dilindungi, sekaligus meminimalkan potensi dampak jika token akses dicuri.
Paket OAuth 2.0 di Library Klien Google API untuk Java dibuat di tujuan umum Library Klien Google OAuth 2.0 untuk Java.
Untuk detailnya, lihat dokumentasi Javadoc untuk paket-paket berikut:
- com.google.api.client.googleapis.auth.oauth2 (dari google-api-client)
- com.google.api.client.googleapis.extensions.appengine.auth.oauth2 (dari google-api-client-appengine)
Konsol API Google
Sebelum dapat mengakses Google API, Anda perlu menyiapkan project di Konsol API Google untuk autentikasi dan penagihan apakah klien Anda adalah aplikasi terinstal, aplikasi seluler, server web, atau klien yang berjalan di {i>browser<i}.
Untuk mendapatkan petunjuk tentang cara menyiapkan kredensial Anda dengan benar, lihat Bantuan Konsol API.
Kredensial
GoogleCredential
GoogleCredential adalah class helper keamanan thread untuk OAuth 2.0 guna mengakses resource yang dilindungi menggunakan token akses. Sebagai contoh, jika sudah memiliki sebuah token akses, Anda dapat membuat permintaan dengan cara berikut:
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken); Plus plus = new Plus.builder(new NetHttpTransport(), GsonFactory.getDefaultInstance(), credential) .setApplicationName("Google-PlusSample/1.0") .build();
Identitas Google App Engine
Kredensial alternatif ini didasarkan pada API Java App Identity Google App Engine. Berbeda dengan kredensial yang digunakan aplikasi klien untuk meminta akses ke data pengguna akhir, App Identity API memberikan akses ke data aplikasi itu sendiri.
Menggunakan AppIdentityCredential (dari google-api-client-appengine). Kredensial ini jauh lebih sederhana karena Google App Engine menangani semua detailnya. Anda hanya menentukan cakupan OAuth 2.0 yang diperlukan.
Kode contoh yang diambil dari 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(); }
Penyimpanan data
Token akses biasanya memiliki tanggal kedaluwarsa 1 jam, setelah itu Anda akan
mendapatkan pesan {i>error<i} jika
Anda mencoba menggunakannya.
GoogleCredential
menangani proses "penyegaran" token, yang berarti mendapatkan
token akses baru. Hal ini dilakukan melalui token refresh yang berumur panjang, yang
biasanya diterima bersama dengan token akses jika Anda menggunakan
Parameter access_type=offline
selama alur kode otorisasi (lihat
GoogleAuthorizationCodeFlow.Builder.setAccessType(String)).
Sebagian besar aplikasi perlu mempertahankan token akses kredensial dan/atau token refresh. Untuk mempertahankan akses kredensial dan/atau token refresh, Anda dapat memberikan implementasi DataStoreFactory Anda sendiri dengan StoredCredential; atau Anda dapat menggunakan salah satu implementasi berikut yang disediakan oleh library:
- AppEngineDataStoreFactory: mempertahankan kredensial menggunakan Google App Engine Data Store API.
- MemoryDataStoreFactory: "bertahan" kredensial dalam memori, yang hanya berguna sebagai penyimpanan jangka pendek selama masa proses.
- FileDataStoreFactory: mempertahankan kredensial dalam file.
Pengguna AppEngine: AppEngineCredentialStore tidak digunakan lagi dan akan segera dihapus. Sebaiknya gunakan AppEngineDataStoreFactory dengan StoredCredential. Jika Anda memiliki kredensial yang disimpan dengan cara lama, Anda dapat menggunakan metode bantuan migrateTo(AppEngineDataStoreFactory) atau migrateTo(DataStore) untuk melakukan migrasi.
Anda dapat menggunakan DataStoreCredentialRefreshListener dan setel untuk kredensial menggunakan GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
Alur kode otorisasi
Gunakan alur kode otorisasi agar pengguna akhir dapat memberikan aplikasi Anda akses ke data mereka yang dilindungi di Google API. Protokol untuk alur ini adalah ditentukan dalam Pemberian Kode Otorisasi.
Alur ini diimplementasikan menggunakan GoogleAuthorizationCodeFlow. Langkah-langkahnya adalah:
- Pengguna akhir login ke aplikasi Anda. Anda harus mengaitkan pengguna tersebut dengan ID pengguna yang unik untuk aplikasi Anda.
- Panggil AuthorizationCodeFlow.loadCredential(String)) berdasarkan ID pengguna untuk memeriksa apakah kredensial pengguna akhir sudah diketahui atau belum. Jika ya, kita sudah selesai.
- Jika tidak, panggil AuthorizationCodeFlow.newAuthorizationUrl() dan mengarahkan browser pengguna akhir ke halaman otorisasi untuk memberikan akses aplikasi ke data yang dilindungi.
- Server otorisasi Google kemudian akan
mengalihkan browser kembali ke
URL alihan yang ditentukan oleh aplikasi Anda, bersama dengan kueri
code
. Gunakan parametercode
untuk meminta token akses menggunakan AuthorizationCodeFlow.newTokenRequest(String)). - Menggunakan AuthorizationCodeFlow.createAndStoreCredential(TokenResponse, String)) untuk menyimpan dan mendapatkan kredensial untuk mengakses sumber daya yang dilindungi.
Atau, jika Anda tidak menggunakan GoogleAuthorizationCodeFlow, Anda dapat menggunakan class di tingkat yang lebih rendah:
- Gunakan DataStore.get(String) untuk memuat kredensial dari toko berdasarkan ID pengguna.
- Gunakan GoogleAuthorizationCodeRequestUrl untuk mengarahkan browser ke halaman otorisasi.
- Gunakan AuthorizationCodeResponseUrl untuk memproses respons otorisasi dan mengurai kode otorisasi.
- Gunakan GoogleAuthorizationCodeTokenRequest untuk meminta token akses dan mungkin token refresh.
- Buat GoogleCredential baru dan simpan menggunakan DataStore.set(String, V).
- Akses resource yang dilindungi menggunakan
GoogleCredential
. Token akses yang sudah tidak berlaku akan otomatis diperbarui menggunakan token refresh (jika ada). Pastikan untuk menggunakan DataStoreCredentialRefreshListener dan tetapkan untuk kredensial menggunakan GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
Saat Anda menyiapkan project di Konsol API Google, Anda pilih di antara kredensial yang berbeda, tergantung pada alur yang Anda gunakan. Untuk mengetahui detail selengkapnya, lihat Menyiapkan OAuth 2.0 dan Skenario OAuth 2.0. Cuplikan kode untuk setiap alur tercantum di bawah ini.
Aplikasi server web
Protokol untuk alur ini dijelaskan di Menggunakan OAuth 2.0 untuk Aplikasi Server Web.
Library ini menyediakan class helper servlet untuk menyederhanakan alur kode otorisasi untuk kasus penggunaan dasar. Anda hanya menyediakan subclass konkret AbstractAuthorizationCodeServlet dan AbstractAuthorizationCodeCallbackServlet (dari google-oauth-client-servlet) dan menambahkannya ke file web.xml Anda. Perhatikan bahwa Anda masih perlu memperhatikan {i>login<i} untuk aplikasi web Anda dan mengekstrak ID pengguna.
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 } }
Aplikasi Google App Engine
Alur kode otorisasi di App Engine hampir identik dengan servlet alur kode otorisasi, tapi kita dapat memanfaatkan metode API Java Pengguna. Pengguna harus login agar Users Java API dapat diaktifkan; informasi tentang mengalihkan pengguna ke halaman {i>login<i} jika mereka belum {i>log in<i}, lihat Keamanan dan Autentikasi (dalam web.xml).
Perbedaan utama dari {i>casing<i} servlet
adalah bahwa Anda memberikan
subclass dari
AbstractAppEngineAuthorizationCodeServlet dan AbstractAppEngineAuthorizationCodeCallbackServlet
(dari google-oauth-client-appengine.
Class ini memperluas class servlet abstrak dan mengimplementasikan metode getUserId
untuk Anda menggunakan Users Java API. AppEngineDataStoreFactory
(dari google-http-client-appengine)
adalah opsi yang tepat untuk mempertahankan kredensial menggunakan Data Google App Engine
Store API.
Contoh yang diambil (sedikit diubah) dari 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(); } }
Untuk contoh tambahan, lihat storage-serviceaccount-appengine-sample.
Akun layanan
GoogleCredential juga mendukung akun layanan. Berbeda dengan kredensial yang digunakan aplikasi klien untuk meminta akses ke data pengguna akhir, Akun Layanan memberikan akses ke data Anda sendiri. Aplikasi klien menandatangani permintaan untuk token akses menggunakan kunci pribadi yang didownload dari Konsol API Google.
Contoh kode yang diambil dari 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(); ...
Untuk contoh tambahan, lihat storage-serviceaccount-cmdline-sample.
Peniruan Identitas
Anda juga dapat menggunakan alur akun layanan untuk meniru identitas pengguna di domain yang milik Anda. Ini sangat mirip dengan alur akun layanan di atas, tetapi Anda selanjutnya panggil GoogleCredential.Builder.setServiceAccountUser(String).
Aplikasi terpasang
Ini adalah alur kode otorisasi command line yang dijelaskan di Menggunakan OAuth 2.0 untuk Aplikasi yang Diinstal.
Contoh cuplikan dari 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"); }
Aplikasi sisi klien
Untuk menggunakan alur klien berbasis browser yang dijelaskan di Menggunakan OAuth 2.0 untuk Aplikasi Sisi Klien, Anda biasanya akan mengikuti langkah-langkah berikut:
- Alihkan pengguna akhir di browser ke halaman otorisasi menggunakan GoogleBrowserClientRequestUrl untuk memberi aplikasi browser akses ke data yang dilindungi pengguna akhir.
- Menggunakan Library Klien Google API untuk JavaScript untuk memproses token akses yang ditemukan dalam fragmen URL di URI pengalihan yang terdaftar di Konsol API Google.
Contoh penggunaan untuk aplikasi 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
Library yang akan digunakan dengan Android:
Jika Anda mengembangkan aplikasi untuk Android dan Google API yang ingin Anda gunakan disertakan di Library Layanan Google Play, menggunakan library tersebut untuk mendapatkan performa dan pengalaman terbaik. Jika Google API yang Anda ingin digunakan dengan Android bukan bagian dari pustaka Layanan Google Play, Anda dapat menggunakan Library Klien Google API untuk Java, yang mendukung Android 4.0 (Ice Cream Sandwich) (atau lebih tinggi), dan dijelaskan di sini. Dukungan untuk Android di Google Library Klien API untuk Java adalah @Beta.
Latar belakang:
Mulai dari Eclair (SDK 2.1), akun pengguna dikelola di perangkat Android menggunakan {i>Account Manager<i}. Semua otorisasi aplikasi Android terpusat dikelola SDK menggunakan AccountManager. Anda menentukan cakupan OAuth 2.0 yang dibutuhkan aplikasi, dan layanan ini menampilkan akses yang akan digunakan.
Cakupan OAuth 2.0 ditentukan melalui parameter authTokenType
sebagai oauth2:
ditambah dengan ruang lingkup. Contoh:
oauth2:https://www.googleapis.com/auth/tasks
Izin ini menentukan akses baca/tulis ke Google Tasks API. Jika Anda memerlukan beberapa Cakupan OAuth 2.0, gunakan daftar yang dipisahkan spasi.
Beberapa API memiliki parameter authTokenType
khusus yang juga berfungsi. Misalnya,
"Mengelola tugas Anda" adalah alias untuk contoh authtokenType
yang ditampilkan di atas.
Anda juga harus menetapkan kunci API dari Konsol API Google. Jika tidak, token yang diberikan AccountManager hanya memberikan kuota anonim, yang biasanya sangat rendah. Sebaliknya, dengan menentukan API Anda akan menerima kuota gratis yang lebih tinggi, dan dapat menyiapkan penagihan untuk penggunaan lebih dari itu.
Contoh cuplikan kode yang diambil dari 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; } }