Agar dapat mengakses layanan online dengan aman, pengguna harus melakukan autentikasi ke layanan—mereka harus memberikan bukti identitasnya. Untuk aplikasi yang mengakses layanan pihak ketiga, masalah keamanan menjadi lebih rumit lagi. Pengguna tidak hanya harus diautentikasi untuk mengakses layanan, tetapi aplikasi juga harus diizinkan untuk bertindak atas nama pengguna.
Cara standar industri untuk menangani autentikasi ke layanan pihak ketiga adalah protokol OAuth2. OAuth2 memberikan nilai tunggal, yang disebut token autentikasi, yang mewakili identitas pengguna dan otorisasi aplikasi untuk bertindak atas nama pengguna. Pelajaran ini menunjukkan cara menghubungkan ke server Google yang mendukung OAuth2. Meskipun layanan Google digunakan sebagai contoh, teknik yang ditunjukkan akan berfungsi pada layanan apa pun yang mendukung protokol OAuth2 dengan benar.
OAuth2 baik digunakan untuk:
- Mendapatkan izin dari pengguna untuk mengakses layanan online menggunakan akun mereka.
- Mengautentikasi ke layanan online atas nama pengguna.
- Menangani error autentikasi.
Mengumpulkan informasi
Untuk mulai menggunakan OAuth2, Anda perlu mengetahui beberapa hal khusus API tentang layanan yang Anda coba akses:
- URL layanan yang ingin Anda akses.
- Cakupan autentikasi, yaitu string yang menentukan jenis akses tertentu yang diminta aplikasi Anda. Misalnya, cakupan autentikasi untuk akses hanya baca ke Google Tasks adalah
View your tasks
, sedangkan cakupan autentikasi untuk akses baca-tulis ke Google Tasks adalahManage your tasks
. - Client ID dan rahasia klien, yaitu string yang mengidentifikasi aplikasi Anda ke layanan. Anda perlu mendapatkan {i>string<i} ini langsung dari pemilik layanan. Google memiliki sistem layanan mandiri untuk mendapatkan client ID dan rahasia.
Meminta izin internet
Untuk aplikasi yang menargetkan Android 6.0 (API level 23) dan yang lebih tinggi, metode
getAuthToken()
tidak memerlukan izin apa pun. Namun, untuk melakukan operasi pada token, Anda harus menambahkan izin INTERNET
ke file manifes, seperti yang ditunjukkan dalam cuplikan kode berikut:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
Meminta token autentikasi
Untuk mendapatkan token, panggil AccountManager.getAuthToken()
.
Perhatian: Karena beberapa operasi akun mungkin melibatkan komunikasi jaringan, sebagian besar metode AccountManager
bersifat asinkron. Artinya, Anda harus menerapkannya sebagai serangkaian callback, bukan melakukan semua pekerjaan autentikasi dalam satu fungsi.
Cuplikan berikut menunjukkan cara menggunakan serangkaian callback untuk mendapatkan token:
Kotlin
val am: AccountManager = AccountManager.get(this) val options = Bundle() am.getAuthToken( myAccount_, // Account retrieved using getAccountsByType() "Manage your tasks", // Auth scope options, // Authenticator-specific options this, // Your activity OnTokenAcquired(), // Callback called when a token is successfully acquired Handler(OnError()) // Callback called if an error occurs )
Java
AccountManager am = AccountManager.get(this); Bundle options = new Bundle(); am.getAuthToken( myAccount_, // Account retrieved using getAccountsByType() "Manage your tasks", // Auth scope options, // Authenticator-specific options this, // Your activity new OnTokenAcquired(), // Callback called when a token is successfully acquired new Handler(new OnError())); // Callback called if an error occurs
Dalam contoh ini, OnTokenAcquired
adalah class yang mengimplementasikan
AccountManagerCallback
. AccountManager
memanggil
run()
di OnTokenAcquired
dengan
AccountManagerFuture
yang berisi Bundle
. Jika panggilan berhasil, token berada di dalam Bundle
.
Berikut adalah cara mendapatkan token dari Bundle
:
Kotlin
private class OnTokenAcquired : AccountManagerCallback<Bundle> { override fun run(result: AccountManagerFuture<Bundle>) { // Get the result of the operation from the AccountManagerFuture. val bundle: Bundle = result.getResult() // The token is a named value in the bundle. The name of the value // is stored in the constant AccountManager.KEY_AUTHTOKEN. val token: String = bundle.getString(AccountManager.KEY_AUTHTOKEN) } }
Java
private class OnTokenAcquired implements AccountManagerCallback<Bundle> { @Override public void run(AccountManagerFuture<Bundle> result) { // Get the result of the operation from the AccountManagerFuture. Bundle bundle = result.getResult(); // The token is a named value in the bundle. The name of the value // is stored in the constant AccountManager.KEY_AUTHTOKEN. String token = bundle.getString(AccountManager.KEY_AUTHTOKEN); ... } }
Jika semuanya berjalan lancar, Bundle
akan berisi token yang valid dalam kunci KEY_AUTHTOKEN
dan Anda sudah siap.
Permintaan pertama Anda untuk token autentikasi mungkin gagal karena beberapa alasan:
- Terjadi error di perangkat atau jaringan yang menyebabkan
AccountManager
gagal. - Pengguna memutuskan untuk tidak memberi aplikasi Anda akses ke akun.
- Kredensial akun yang tersimpan tidak memadai untuk mendapatkan akses ke akun.
- Token autentikasi cache telah habis masa berlakunya.
Aplikasi dapat menangani dua kasus pertama dengan mudah, biasanya cukup dengan menampilkan pesan error kepada pengguna. Jika jaringan tidak aktif atau pengguna memutuskan untuk tidak memberikan akses, tidak banyak yang dapat dilakukan aplikasi Anda terkait hal ini. Dua kasus terakhir sedikit lebih rumit, karena aplikasi yang berperilaku baik diharapkan dapat menangani kegagalan ini secara otomatis.
Kasus kegagalan ketiga, kredensial yang tidak memadai, dikomunikasikan melalui
Bundle
yang Anda terima dalam AccountManagerCallback
(OnTokenAcquired
dari contoh sebelumnya). Jika Bundle
menyertakan Intent
dalam kunci KEY_INTENT
, pengautentikasi akan memberi tahu Anda bahwa ia perlu berinteraksi langsung dengan pengguna agar dapat memberi Anda token yang valid.
Ada banyak alasan mengapa pengautentikasi menampilkan Intent
. Mungkin ini pertama kalinya pengguna login ke akun ini. Mungkin akun pengguna telah habis masa berlakunya dan mereka harus login lagi, atau mungkin kredensial yang mereka simpan salah. Mungkin akun tersebut memerlukan autentikasi 2 langkah atau perlu mengaktifkan kamera untuk melakukan pemindaian retina. Apa pun alasannya. Jika menginginkan token yang valid, Anda harus mengaktifkan Intent
untuk mendapatkannya.
Kotlin
private inner class OnTokenAcquired : AccountManagerCallback<Bundle> { override fun run(result: AccountManagerFuture<Bundle>) { val launch: Intent? = result.getResult().get(AccountManager.KEY_INTENT) as? Intent if (launch != null) { startActivityForResult(launch, 0) } } }
Java
private class OnTokenAcquired implements AccountManagerCallback<Bundle> { @Override public void run(AccountManagerFuture<Bundle> result) { ... Intent launch = (Intent) result.getResult().get(AccountManager.KEY_INTENT); if (launch != null) { startActivityForResult(launch, 0); return; } } }
Perhatikan bahwa contoh tersebut menggunakan startActivityForResult()
, sehingga Anda dapat menangkap
hasil Intent
dengan mengimplementasikan onActivityResult()
dalam
aktivitas Anda sendiri. Hal ini penting: Jika tidak mengambil hasilnya dari Intent
respons pengautentikasi,
Anda tidak akan bisa mengetahui apakah pengguna telah berhasil diautentikasi.
Jika hasilnya adalah RESULT_OK
, pengautentikasi telah memperbarui kredensial yang disimpan agar memadai untuk tingkat akses yang Anda minta, dan Anda harus memanggil AccountManager.getAuthToken()
lagi untuk meminta token autentikasi baru.
Kasus terakhir, saat masa berlaku token telah berakhir, sebenarnya bukan kegagalan AccountManager
. Satu-satunya cara untuk mengetahui apakah masa berlaku token telah berakhir adalah dengan menghubungi server, dan akan sia-sia serta mahal bagi AccountManager
jika terus online untuk memeriksa status semua tokennya. Jadi, ini adalah kegagalan yang hanya dapat dideteksi ketika aplikasi seperti milik Anda mencoba menggunakan token autentikasi untuk mengakses layanan online.
Menghubungkan ke layanan online
Contoh di bawah ini menunjukkan cara membuat sambungan ke server Google. Karena Google menggunakan protokol OAuth2 standar industri untuk mengautentikasi permintaan, teknik yang dibahas di sini dapat diterapkan secara luas. Namun, perlu diingat bahwa setiap server berbeda. Anda mungkin perlu melakukan sedikit penyesuaian pada petunjuk ini untuk memperhitungkan situasi spesifik Anda.
Google API mengharuskan Anda memberikan empat nilai bersama setiap permintaan: kunci API, client ID, rahasia klien, dan kunci autentikasi. Tiga yang pertama berasal dari situs Konsol API Google. Yang terakhir adalah nilai string yang Anda
peroleh dengan memanggil AccountManager.getAuthToken()
. Anda meneruskannya ke Server Google sebagai bagian dari permintaan HTTP.
Kotlin
val url = URL("https://www.googleapis.com/tasks/v1/users/@me/lists?key=$your_api_key") val conn = url.openConnection() as HttpURLConnection conn.apply { addRequestProperty("client_id", your client id) addRequestProperty("client_secret", your client secret) setRequestProperty("Authorization", "OAuth $token") }
Java
URL url = new URL("https://www.googleapis.com/tasks/v1/users/@me/lists?key=" + your_api_key); URLConnection conn = (HttpURLConnection) url.openConnection(); conn.addRequestProperty("client_id", your client id); conn.addRequestProperty("client_secret", your client secret); conn.setRequestProperty("Authorization", "OAuth " + token);
Jika permintaan ini menampilkan kode error HTTP 401, berarti token Anda ditolak. Seperti yang disebutkan di bagian terakhir, alasan paling umum terjadinya hal ini adalah masa berlaku token telah berakhir. Perbaikannya
mudah: panggil
AccountManager.invalidateAuthToken()
dan
ulangi proses akuisisi token sekali
lagi.
Karena token yang habis masa berlakunya sudah biasa terjadi, dan memperbaikinya sangatlah mudah, banyak aplikasi berasumsi bahwa token telah habis masa berlakunya bahkan sebelum memintanya. Jika memperpanjang token adalah operasi yang murah bagi server, Anda dapat memanggil AccountManager.invalidateAuthToken()
sebelum panggilan pertama ke AccountManager.getAuthToken()
, dan tidak perlu meminta token autentikasi dua kali.