Online bir hizmete güvenli bir şekilde erişmek için kullanıcıların hizmette kimlik doğrulaması yapması, ancak kimlik belgelerini sunması gerekir. Üçüncü taraf hizmetlerine erişen bir uygulama için güvenlik sorunu daha da karmaşıktır. Hizmete erişmek için kullanıcının kimliğinin doğrulanmasının yanı sıra uygulamanın, kullanıcı adına işlem yapma yetkisine de sahip olması gerekir.
Üçüncü taraf hizmetlerine kimlik doğrulama işlemi için endüstri standardı olan yöntem OAuth2 protokolüdür. OAuth2, hem kullanıcı kimliğini hem de uygulamanın kullanıcı adına hareket etme yetkisini temsil eden ve yetkilendirme jetonu adı verilen tek bir değer sağlar. Bu derste, OAuth2'yi destekleyen bir Google sunucusuna bağlanma gösterilmektedir. Örnek olarak Google hizmetleri kullanılsa da gösterilen teknikler OAuth2 protokolünü doğru bir şekilde destekleyen tüm hizmetlerde çalışacaktır.
OAuth2 kullanmak şunlar için yararlıdır:
- Kullanıcıdan hesabını kullanarak online bir hizmete erişim izni almak.
- Kullanıcı adına bir online hizmet için kimlik doğrulama.
- Kimlik doğrulama hatalarını işleme.
Bilgi toplama
OAuth2'yi kullanmaya başlamak için, erişmeye çalıştığınız hizmet hakkında API'ye özgü birkaç noktayı bilmeniz gerekir:
- Erişmek istediğiniz hizmetin URL'si.
- Uygulamanızın istediği belirli erişim türünü tanımlayan bir dize olan kimlik doğrulama kapsamı. Örneğin, Google Görevler'e salt okuma erişimi için kimlik doğrulama kapsamı
View your tasks
, Google Görevler'e okuma-yazma erişimi için kimlik doğrulama kapsamı iseManage your tasks
'dir. - İstemci kimliği ve istemci gizli anahtarı. Uygulamanızı hizmete tanımlayan dizelerdir. Bu dizeleri doğrudan hizmet sahibinden almanız gerekir. Google, istemci kimliklerini ve gizli anahtarları edinmek için kullanılan self servis bir sisteme sahiptir.
İnternet izni isteme
Android 6.0 (API düzeyi 23) ve sonraki sürümleri hedefleyen uygulamalar için getAuthToken()
yönteminin kendisi herhangi bir izin gerektirmez. Ancak jeton üzerinde işlem gerçekleştirmek için aşağıdaki kod snippet'inde gösterildiği gibi manifest dosyanıza INTERNET
iznini eklemeniz gerekir:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
Yetkilendirme jetonu isteme
Jetonu almak için AccountManager.getAuthToken()
numaralı telefonu arayın.
Dikkat: Bazı hesap işlemleri ağ iletişimi içerebileceği için AccountManager
yöntemlerinin çoğu eşzamansızdır. Diğer bir deyişle, tüm kimlik doğrulama işlemlerinizi tek bir işlevde yapmak yerine, bu işlevi bir dizi geri çağırma olarak uygulamanız gerekir.
Aşağıdaki snippet'te, jetonu almak için bir dizi geri çağırmayla nasıl çalışacağınız gösterilmektedir:
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
Bu örnekte, OnTokenAcquired
, AccountManagerCallback
uygulayan bir sınıftır. AccountManager
, Bundle
içeren bir AccountManagerFuture
ile OnTokenAcquired
üzerinde run()
çağrısı yapar. Çağrı başarılı olursa jeton Bundle
içindedir.
Bundle
hizmetinden nasıl jeton alabileceğiniz aşağıda açıklanmıştır:
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); ... } }
Her şey yolunda giderse Bundle
, KEY_AUTHTOKEN
anahtarında geçerli bir jeton içerir ve artık hazırsınız demektir.
İlk yetkilendirme jetonu isteğiniz çeşitli nedenlerden dolayı başarısız olabilir:
- Cihazdaki veya ağdaki bir hata
AccountManager
cihazının başarısız olmasına neden oldu. - Kullanıcı, uygulamanızın hesaba erişmesine izin vermemeye karar vermiştir.
- Depolanan hesap kimlik bilgileri, hesaba erişmek için yeterli değildir.
- Önbelleğe alınan yetkilendirme jetonunun süresi doldu.
Uygulamalar ilk iki durumu, genellikle kullanıcıya bir hata mesajı göstererek önemsiz bir şekilde ele alabilir. Ağ devre dışıysa veya kullanıcı erişim izni vermemeye karar verdiyse uygulamanızın bu konuda yapabileceği pek bir şey yoktur. Son iki durum biraz daha karmaşıktır, çünkü uyumlu uygulamaların bu hataları otomatik olarak ele alması beklenir.
Yetersiz kimlik bilgilerine sahip üçüncü hata durumu, AccountManagerCallback
içinde aldığınız Bundle
aracılığıyla iletilir (bir önceki örnekten OnTokenAcquired
). Bundle
öğesinin KEY_INTENT
anahtarında Intent
bulunuyorsa kimlik doğrulayıcı, size geçerli bir jeton vermeden önce kullanıcıyla doğrudan etkileşimde bulunması gerektiğini bildiriyor.
Kimlik doğrulayıcının bir Intent
döndürmesinin birçok nedeni olabilir. Kullanıcı, bu hesaba ilk kez giriş yapıyor olabilir. Kullanıcının hesabının süresi dolmuş ve tekrar giriş yapması gerekiyor ya da saklanan kimlik bilgileri yanlış olabilir. Belki hesap, iki faktörlü kimlik doğrulama gerektiriyordur veya retina taraması için kamerayı etkinleştirmesi gerekiyordur. Sebebinin ne olduğu pek önemli değildir. Geçerli bir jeton istiyorsanız bunu almak için Intent
ile tetiklenmeniz gerekir.
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; } } }
Örneğin startActivityForResult()
kullandığını unutmayın. Böylece kendi etkinliğinize onActivityResult()
uygulayarak Intent
sonucunu yakalayabilirsiniz. Bu önemlidir: Kimlik doğrulayıcının Intent
yanıtına ait sonucu almazsanız kullanıcının kimlik doğrulamasının başarıyla yapılmış olup olmadığını anlamak imkansızdır.
Sonuç RESULT_OK
ise kimlik doğrulayıcı, depolanan kimlik bilgilerini istediğiniz erişim düzeyi için yeterli olacak şekilde güncellemiştir. Bu durumda, yeni kimlik doğrulama jetonunu istemek için AccountManager.getAuthToken()
yöntemini tekrar çağırmanız gerekir.
Jetonun süresinin dolduğu son durum aslında bir AccountManager
hatası değildir. Bir jetonun süresinin dolup dolmadığını öğrenmenin tek yolu sunucuyla iletişime geçmektir. Bu durum, AccountManager
adlı jetonun tüm jetonlarının durumunu kontrol etmek için sürekli olarak internete bağlanmak gereksiz ve pahalı olur. Bu hata, yalnızca sizinkine benzer bir uygulama online bir hizmete erişmek için kimlik doğrulama jetonunu kullanmaya çalıştığında algılanabilir.
Online hizmete bağlanma
Aşağıdaki örnekte, bir Google sunucusuna nasıl bağlanılacağı gösterilmektedir. Google, isteklerin kimliğini doğrulamak için endüstri standardı OAuth2 protokolünü kullandığından, burada açıklanan teknikler geniş ölçüde uygulanabilir. Yine de, her sunucunun farklı olduğunu unutmayın. Özel durumunuzu açıklamak için bu talimatlarda küçük ayarlamalar yapmanız gerekebilir.
Google API'leri her istekle birlikte dört değer sağlamanızı gerektirir: API anahtarı, istemci kimliği, istemci gizli anahtarı ve kimlik doğrulama anahtarı. İlk üçü Google API Konsolu web sitesinden gelir. Sonuncusu, AccountManager.getAuthToken()
yöntemini çağırarak elde ettiğiniz dize değeridir. Bunları bir HTTP isteğinin parçası olarak Google Sunucusu'na geçirirsiniz.
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);
İstek 401 HTTP hata kodu döndürürse jetonunuz reddedilmiştir. Son bölümde belirtildiği gibi, bunun en yaygın nedeni jetonun süresinin dolmasıdır. Çözüm basittir: AccountManager.invalidateAuthToken()
çağrısı yapın ve jeton edinme işlemini bir kez daha tekrarlayın.
Süresi dolmuş jetonlar sık karşılaşılan bir durum olduğu ve bunları düzeltmek çok kolay olduğu için birçok uygulama, daha sormadan jetonun süresinin dolduğunu varsayar. Jeton yenilemek, sunucunuz için ucuz bir işlemse AccountManager.getAuthToken()
için yapılan ilk çağrıdan önce AccountManager.invalidateAuthToken()
yöntemini çağırmayı tercih edebilir ve iki kez yetkilendirme jetonu isteme ihtiyacından kurtulabilirsiniz.