Ringkasan
Tujuan: Dokumen ini menjelaskan cara menggunakan class utilitas GoogleCredential untuk melakukan otorisasi OAuth 2.0 dengan layanan Google. Untuk informasi tentang fungsi OAuth 2.0 generik yang kami sediakan, lihat OAuth 2.0 dan Library Klien OAuth Google untuk Java.
Ringkasan: Untuk mengakses data terlindungi yang disimpan di layanan Google, gunakan OAuth 2.0 untuk otorisasi. Google API mendukung alur OAuth 2.0 untuk berbagai jenis aplikasi klien. Dalam semua alur ini, aplikasi klien meminta token akses yang hanya terkait dengan aplikasi klien Anda dan pemilik data yang dilindungi yang 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 OAuth 2.0 adalah untuk memberikan akses yang aman dan nyaman ke data yang dilindungi, sekaligus meminimalkan potensi dampak jika token akses dicuri.
Paket OAuth 2.0 di Library Klien Google API untuk Java dibangun berdasarkan Library Klien OAuth 2.0 Google untuk Java serbaguna.
Untuk mengetahui detailnya, lihat dokumentasi Javadoc untuk 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 tujuan otorisasi dan penagihan, baik klien Anda adalah aplikasi yang diinstal, aplikasi seluler, server web, atau klien yang berjalan di browser.
Untuk mengetahui petunjuk tentang cara menyiapkan kredensial dengan benar, lihat Bantuan Konsol API.
Kredensial
GoogleCredential
GoogleCredential adalah class helper yang aman untuk thread untuk OAuth 2.0 dalam mengakses resource yang dilindungi menggunakan token akses. Misalnya, jika sudah memiliki 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 Google App Engine App Identity Java API. Tidak seperti kredensial yang digunakan aplikasi klien untuk meminta akses ke data pengguna akhir, App Identity API memberikan akses ke data aplikasi klien itu sendiri.
Gunakan 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 Anda butuhkan.
Contoh kode 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 habis masa berlaku 1 jam, setelah itu Anda akan
mendapatkan error jika mencoba menggunakannya.
GoogleCredential
akan menangani "refresh" token secara otomatis, yang berarti hanya mendapatkan
token akses baru. Hal ini dilakukan dengan menggunakan token refresh yang berlaku lama, 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 dan/atau token refresh kredensial. Untuk mempertahankan akses dan/atau token refresh kredensial, Anda dapat menyediakan implementasi DataStoreFactory 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: "mempertahankan" kredensial dalam memori, yang hanya berguna sebagai penyimpanan jangka pendek selama masa aktif proses.
- FileDataStoreFactory: mempertahankan kredensial dalam file.
Pengguna AppEngine: AppEngineCredentialStore tidak digunakan lagi dan akan segera dihapus. Sebaiknya Anda menggunakan AppEngineDataStoreFactory dengan StoredCredential. Jika memiliki kredensial yang disimpan dengan cara lama, Anda dapat menggunakan metode bantuan yang ditambahkan migrateTo(AppEngineDataStoreFactory) atau migrateTo(DataStore) untuk melakukan migrasi.
Anda dapat menggunakan DataStoreCredentialRefreshListener dan menyetelnya untuk kredensial menggunakan GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
Alur kode otorisasi
Gunakan alur kode otorisasi untuk mengizinkan pengguna akhir memberikan akses aplikasi Anda ke data terlindung mereka di Google API. Protokol untuk alur ini ditentukan dalam Authorization Code Grant.
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. Jika ya, kita sudah selesai.
- Jika tidak, panggil AuthorizationCodeFlow.newAuthorizationUrl() dan arahkan browser pengguna akhir ke halaman otorisasi untuk memberikan akses aplikasi Anda ke data terlindung mereka.
- Server otorisasi Google kemudian akan mengalihkan browser kembali ke
URL pengalihan yang ditentukan oleh aplikasi Anda, beserta parameter kueri
code. Gunakan parametercodeuntuk meminta token akses menggunakan AuthorizationCodeFlow.newTokenRequest(String)). - Gunakan AuthorizationCodeFlow.createAndStoreCredential(TokenResponse, String)) untuk menyimpan dan mendapatkan kredensial untuk mengakses resource yang dilindungi.
Atau, jika Anda tidak menggunakan GoogleAuthorizationCodeFlow, Anda dapat menggunakan class tingkat yang lebih rendah:
- Gunakan DataStore.get(String) untuk memuat kredensial dari penyimpanan 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 telah habis masa berlakunya akan otomatis diperbarui menggunakan token refresh (jika ada). Pastikan untuk menggunakan DataStoreCredentialRefreshListener dan menyetelnya untuk kredensial menggunakan GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
Saat menyiapkan project di Konsol Google API, Anda memilih kredensial yang berbeda, bergantung pada alur yang Anda gunakan. Untuk mengetahui detail selengkapnya, lihat Menyiapkan OAuth 2.0 dan Skenario OAuth 2.0. Cuplikan kode untuk setiap alur ada di bawah.
Aplikasi server web
Protokol untuk alur ini dijelaskan dalam Menggunakan OAuth 2.0 untuk Aplikasi Server Web.
Library ini menyediakan class helper servlet untuk menyederhanakan alur kode otorisasi secara signifikan untuk kasus penggunaan dasar. Anda hanya perlu menyediakan subclass konkret dari AbstractAuthorizationCodeServlet dan AbstractAuthorizationCodeCallbackServlet (dari google-oauth-client-servlet) lalu menambahkannya ke file web.xml Anda. Perhatikan bahwa Anda masih perlu menangani login pengguna untuk aplikasi web 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 alur kode otorisasi servlet, kecuali kita dapat memanfaatkan Users Java API Google App Engine. Pengguna harus login agar Users Java API dapat diaktifkan; untuk mengetahui informasi tentang mengalihkan pengguna ke halaman login jika mereka belum login, lihat Security and Authentication (di web.xml).
Perbedaan utama dari kasus servlet adalah Anda menyediakan subclass konkret 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 baik untuk mempertahankan kredensial menggunakan Google App Engine Data
Store API.
Contoh diambil (sedikit dimodifikasi) 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. Tidak seperti kredensial yang digunakan aplikasi klien untuk meminta akses ke data pengguna akhir, Akun Layanan memberikan akses ke data aplikasi klien itu sendiri. Aplikasi klien Anda menandatangani permintaan token akses menggunakan kunci pribadi yang didownload dari Konsol API Google.
Contoh Penggunaan:
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(); ...
Untuk contoh tambahan, lihat storage-serviceaccount-cmdline-sample.
Peniruan Identitas
Anda juga dapat menggunakan alur akun layanan untuk meniru identitas pengguna di domain yang Anda miliki. Hal ini sangat mirip dengan alur akun layanan di atas, tetapi Anda juga memanggil GoogleCredential.Builder.setServiceAccountUser(String).
Aplikasi terpasang
Ini adalah alur kode otorisasi command line yang dijelaskan dalam Menggunakan OAuth 2.0 untuk Aplikasi yang Diinstal.
Contoh penggunaan:
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"); }
Aplikasi sisi klien
Untuk menggunakan alur klien berbasis browser yang dijelaskan dalam 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 memberikan akses aplikasi browser Anda ke data terlindungi pengguna akhir.
- Gunakan Library Klien Google API untuk JavaScript guna memproses token akses yang ditemukan di fragmen URL pada 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 dalam library Layanan Google Play, gunakan library tersebut untuk mendapatkan performa dan pengalaman terbaik. Jika Google API yang ingin Anda gunakan dengan Android bukan bagian dari library Layanan Google Play, Anda dapat menggunakan Google API Client Library untuk Java, yang mendukung Android 4.0 (Ice Cream Sandwich) (atau yang lebih tinggi), dan yang dijelaskan di sini. Dukungan untuk Android di Library Klien Google API untuk Java adalah @Beta.
Latar belakang:
Mulai dari Eclair (SDK 2.1), akun pengguna dikelola di perangkat Android menggunakan Account Manager. Semua otorisasi aplikasi Android dikelola secara terpusat oleh SDK menggunakan AccountManager. Anda menentukan cakupan OAuth 2.0 yang dibutuhkan aplikasi Anda, dan API ini akan menampilkan token akses untuk digunakan.
Cakupan OAuth 2.0 ditentukan melalui parameter authTokenType sebagai oauth2:
ditambah cakupan. Contoh:
oauth2:https://www.googleapis.com/auth/tasks
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,
"Kelola tugas Anda" adalah alias untuk contoh authtokenType yang ditampilkan di atas.
Anda juga harus menentukan kunci API dari Konsol Google API. Jika tidak, token yang diberikan AccountManager hanya memberi Anda kuota anonim, yang biasanya sangat rendah. Sebaliknya, dengan menentukan kunci API, Anda akan menerima kuota gratis yang lebih tinggi, dan secara opsional dapat menyiapkan penagihan untuk penggunaan di atas kuota tersebut.
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; } }