Kimlik doğrulama, bir kişinin kim olduğunu belirler ve genellikle kullanıcı kaydı veya oturum açma olarak adlandırılır. Yetkilendirme, verilere veya kaynaklara erişim izni verme ya da erişimi reddetme işlemidir. Örneğin, uygulamanız kullanıcının Google Drive'ına erişmek için kullanıcının iznini ister.
Kimlik doğrulama ve yetkilendirme çağrıları, uygulamanın ihtiyaçlarına göre iki ayrı ve farklı akış olmalıdır.
Uygulamanızda Google API verilerinden yararlanabilen ancak uygulamanızın temel özellikleri kapsamında zorunlu olmayan özellikler varsa uygulamanızı, API verilerine erişilemediği durumları sorunsuz bir şekilde işleyebilecek şekilde tasarlamanız gerekir. Örneğin, kullanıcı Drive erişimi vermediğinde yakın zamanda kaydedilen dosyaların listesini gizleyebilirsiniz.
Google API'lerine erişmek için yalnızca kullanıcının belirli bir API'ye erişim gerektiren bir işlem gerçekleştirdiği durumlarda ihtiyacınız olan kapsamlar için erişim isteğinde bulunmalısınız. Örneğin, kullanıcı "Drive'a kaydet" düğmesine her dokunduğunda kullanıcının Drive'ına erişmek için izin istemeniz gerekir.
Yetkilendirmeyi kimlik doğrulamadan ayırarak yeni kullanıcıların kafasını karıştırmayı veya kullanıcılardan neden belirli izinler istendiği konusunda kafa karışıklığı yaşanmasını önleyebilirsiniz.
Kimlik doğrulama için Credential Manager API'yi kullanmanızı öneririz. Google tarafından depolanan kullanıcı verilerine erişim gerektiren işlemleri yetkilendirmek için AuthorizationClient'ı kullanmanızı öneririz.
Projenizi oluşturma
- Projenizi 'da açın veya henüz projeniz yoksa proje oluşturun.
- bölümünde tüm bilgilerin eksiksiz ve doğru olduğundan emin olun.
- Uygulamanızın doğru bir uygulama adı, uygulama logosu ve uygulama ana sayfası atandığından emin olun. Bu değerler, kayıt sırasında Google ile oturum açma izni ekranında ve Üçüncü taraf uygulamaları ve hizmetleri ekranında kullanıcılara gösterilir.
- Uygulamanızın gizlilik politikası ve hizmet şartları URL'lerini belirttiğinizden emin olun.
- 'da henüz yoksa uygulamanız için bir Android istemci kimliği oluşturun. Uygulamanızın paket adını ve SHA-1 imzasını belirtmeniz gerekir.
- bölümünde, henüz yapmadıysanız yeni bir "Web uygulaması" istemci kimliği oluşturun. Şimdilik "Yetkilendirilmiş JavaScript Kaynakları" ve "Yetkilendirilmiş yönlendirme URI'leri" alanlarını yok sayabilirsiniz. Bu istemci kimliği, arka uç sunucunuz Google'ın kimlik doğrulama hizmetleriyle iletişim kurduğunda sunucunuzu tanımlamak için kullanılır.
Bağımlılıkları bildirme
Modülünüzün build.gradle dosyasında, Google Identity Services kitaplığının en yeni sürümünü kullanarak bağımlılıkları bildirin.
dependencies {
// ... other dependencies
implementation "com.google.android.gms:play-services-auth:21.4.0"
}
Kullanıcı işlemleri için gerekli izinleri isteme
Kullanıcı, ek kapsam gerektiren bir işlem gerçekleştirdiğinde AuthorizationClient.authorize()
işlevini çağırın. Örneğin, bir kullanıcı Drive uygulama depolama alanına erişim gerektiren bir işlem yaparsa şunları yapın:
Kotlin
val requestedScopes: List<Scope> = listOf(DriveScopes.DRIVE_FILE)
val authorizationRequest = AuthorizationRequest.builder()
.setRequestedScopes(requestedScopes)
.build()
Identity.getAuthorizationClient(activity)
.authorize(authorizationRequestBuilder.build())
.addOnSuccessListener { authorizationResult ->
if (authorizationResult.hasResolution()) {
val pendingIntent = authorizationResult.pendingIntent
// Access needs to be granted by the user
startAuthorizationIntent.launchIntentSenderRequest.Builder(pendingIntent!!.intentSender).build()
} else {
// Access was previously granted, continue with user action
saveToDriveAppFolder(authorizationResult);
}
}
.addOnFailureListener { e -> Log.e(TAG, "Failed to authorize", e) }
Java
List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_FILE);
AuthorizationRequest authorizationRequest = AuthorizationRequest.builder()
.setRequestedScopes(requestedScopes)
.build();
Identity.getAuthorizationClient(activity)
.authorize(authorizationRequest)
.addOnSuccessListener(authorizationResult -> {
if (authorizationResult.hasResolution()) {
// Access needs to be granted by the user
startAuthorizationIntent.launch(
new IntentSenderRequest.Builder(
authorizationResult.getPendingIntent().getIntentSender()
).build()
);
} else {
// Access was previously granted, continue with user action
saveToDriveAppFolder(authorizationResult);
}
})
.addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));
ActivityResultLauncher
tanımlanırken yanıtı aşağıdaki snippet'te gösterildiği gibi işleyin. Burada, işlemin bir parçada yapıldığını varsayıyoruz. Kod, gerekli izinlerin başarıyla verilip verilmediğini kontrol eder ve ardından kullanıcı işlemini gerçekleştirir.
Kotlin
private lateinit var startAuthorizationIntent: ActivityResultLauncher<IntentSenderRequest>
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
// ...
startAuthorizationIntent =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->
try {
// extract the result
val authorizationResult = Identity.getAuthorizationClient(requireContext())
.getAuthorizationResultFromIntent(activityResult.data)
// continue with user action
saveToDriveAppFolder(authorizationResult);
} catch (ApiException e) {
// log exception
}
}
}
Java
private ActivityResultLauncher<IntentSenderRequest> startAuthorizationIntent;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// ...
startAuthorizationIntent =
registerForActivityResult(
new ActivityResultContracts.StartIntentSenderForResult(),
activityResult -> {
try {
// extract the result
AuthorizationResult authorizationResult =
Identity.getAuthorizationClient(requireActivity())
.getAuthorizationResultFromIntent(activityResult.getData());
// continue with user action
saveToDriveAppFolder(authorizationResult);
} catch (ApiException e) {
// log exception
}
});
}
Google API'lerine sunucu tarafında erişiyorsanız getServerAuthCode()
yöntemini AuthorizationResult
üzerinden çağırarak bir yetkilendirme kodu alın. Bu kodu, erişim ve yenileme jetonuyla değiştirmek için arka ucunuza gönderirsiniz. Daha fazla bilgi için Kullanıcı verilerine sürekli erişimi sürdürme başlıklı makaleyi inceleyin.
Kullanıcı verilerine veya kaynaklarına yönelik izinleri iptal etme
Daha önce verilen erişimi iptal etmek için AuthorizationClient.revokeAccess()
numaralı telefonu arayın. Örneğin, kullanıcı hesabını uygulamanızdan kaldırıyorsa ve uygulamanıza daha önce DriveScopes.DRIVE_FILE
erişim izni verildiyse erişimi iptal etmek için aşağıdaki kodu kullanın:
Kotlin
val requestedScopes: MutableList<Scope> = mutableListOf(DriveScopes.DRIVE_FILE)
RevokeAccessRequest revokeAccessRequest = RevokeAccessRequest.builder()
.setAccount(account)
.setScopes(requestedScopes)
.build()
Identity.getAuthorizationClient(activity)
.revokeAccess(revokeAccessRequest)
.addOnSuccessListener { Log.i(TAG, "Successfully revoked access") }
.addOnFailureListener { e -> Log.e(TAG, "Failed to revoke access", e) }
Java
List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_FILE);
RevokeAccessRequest revokeAccessRequest = RevokeAccessRequest.builder()
.setAccount(account)
.setScopes(requestedScopes)
.build();
Identity.getAuthorizationClient(activity)
.revokeAccess(revokeAccessRequest)
.addOnSuccessListener(unused -> Log.i(TAG, "Successfully revoked access"))
.addOnFailureListener(e -> Log.e(TAG, "Failed to revoke access", e));
Jeton önbelleğini temizleme
OAuth erişim jetonları, sunucudan alındıktan sonra yerel olarak önbelleğe alınır. Bu sayede erişim hızlandırılır ve ağ çağrıları azaltılır. Bu jetonlar, süreleri dolduğunda önbellekten otomatik olarak silinir ancak başka nedenlerle de geçersiz hale gelebilir.
Bir jeton kullanırken IllegalStateException
hatası alırsanız erişim jetonu için bir sonraki yetkilendirme isteğinin OAuth sunucusuna gönderildiğinden emin olmak için yerel önbelleği temizleyin. Aşağıdaki snippet, yerel önbellekten invalidAccessToken
öğesini kaldırır:
Kotlin
Identity.getAuthorizationClient(activity)
.clearToken(ClearTokenRequest.builder().setToken(invalidAccessToken).build())
.addOnSuccessListener { Log.i(TAG, "Successfully removed the token from the cache") }
.addOnFailureListener{ e -> Log.e(TAG, "Failed to clear token", e) }
Java
Identity.getAuthorizationClient(activity)
.clearToken(ClearTokenRequest.builder().setToken(invalidAccessToken).build())
.addOnSuccessListener(unused -> Log.i(TAG, "Successfully removed the token from the cache"))
.addOnFailureListener(e -> Log.e(TAG, "Failed to clear the token cache", e));
Yetkilendirme sırasında kullanıcı bilgilerini alma
Yetkilendirme yanıtı, kullanılan kullanıcı hesabı hakkında herhangi bir bilgi içermiyor. Yanıtta yalnızca istenen kapsamlar için bir jeton bulunuyor. Örneğin, kullanıcının Google Drive'ına erişmek için erişim jetonu alma yanıtı, kullanıcının seçtiği hesabın kimliğini ortaya çıkarmaz. Ancak bu yanıt, kullanıcının Drive'ındaki dosyalara erişmek için kullanılabilir. Kullanıcının adı veya e-posta adresi gibi bilgileri almak için aşağıdaki seçenekleri kullanabilirsiniz:
Yetkilendirme istemeden önce Kimlik Bilgisi Yöneticisi API'lerini kullanarak kullanıcının Google Hesabı ile oturum açmasını sağlayın. Kimlik bilgisi yöneticisinden gelen kimlik doğrulama yanıtı, e-posta adresi gibi kullanıcı bilgilerini içerir ve uygulamanın varsayılan hesabını seçilen hesap olarak ayarlar. Gerekirse bu hesabı uygulamanızda izleyebilirsiniz. Sonraki bir yetkilendirme isteğinde hesap varsayılan olarak kullanılır ve yetkilendirme akışındaki hesap seçimi adımı atlanır. Yetkilendirme için farklı bir hesap kullanmak istiyorsanız Varsayılan olmayan bir hesaptan yetkilendirme başlıklı makaleyi inceleyin.
Yetkilendirme isteğinizde, istediğiniz kapsamların (örneğin,
Drive scope
) yanı sırauserinfo
,profile
veopenid
kapsamlarını da isteyin. Erişim jetonu döndürüldükten sonra, tercih ettiğiniz HTTP kitaplığını kullanarak ve başlığa aldığınız erişim jetonunu ekleyerekGET
OAuth userinfo uç noktasına (https://www.googleapis.com/oauth2/v3/userinfo) bir HTTP isteği göndererekcurl
kullanıcı bilgilerini alın. Bu işlem, aşağıdakicurl
komutuna eşdeğerdir:curl -X GET \ "https://www.googleapis.com/oauth2/v1/userinfo?alt=json" \ -H "Authorization: Bearer $TOKEN"
Yanıt, istenen kapsamlarla sınırlı olan ve JSON biçiminde biçimlendirilmiş
UserInfo
'dir.
Varsayılan olmayan bir hesaptan yetkilendirme
Kimlik doğrulamak için Kimlik Bilgisi Yöneticisi'ni kullanıyorsanız ve AuthorizationClient.authorize()
komutunu çalıştırıyorsanız uygulamanızın varsayılan hesabı, kullanıcınız tarafından seçilen hesap olarak ayarlanır. Bu nedenle, sonraki tüm yetkilendirme çağrıları bu varsayılan hesabı kullanır. Hesap seçicinin gösterilmesini zorlamak için
Credential Manager'daki clearCredentialState()
API'sini kullanarak kullanıcının uygulamadaki oturumunu kapatın.
Kullanıcının verilerine sürekli erişimi sürdürme
Uygulamanızdan kullanıcının verilerine erişmeniz gerekiyorsa AuthorizationClient.authorize()
yöntemini bir kez çağırın. Sonraki oturumlarda ve verilen izinler kullanıcı tarafından kaldırılmadığı sürece, hedeflerinize ulaşmak için erişim jetonu almak üzere aynı yöntemi kullanıcı etkileşimi olmadan çağırın. Diğer yandan, kullanıcının verilerine arka uç sunucunuzdan çevrimdışı modda erişmeniz gerekiyorsa "yenileme jetonu" adı verilen farklı bir jeton türü istemeniz gerekir.
Erişim jetonları, kasıtlı olarak kısa süreli olacak şekilde tasarlanır ve bir saatlik bir kullanım ömrüne sahiptir. Bir erişim jetonu ele geçirilirse veya güvenliği ihlal edilirse sınırlı geçerlilik süresi, olası kötüye kullanımı en aza indirir. Süresi dolduktan sonra jeton geçersiz hale gelir ve jetonu kullanma girişimleri kaynak sunucusu tarafından reddedilir. Erişim jetonları kısa ömürlü olduğundan sunucular, kullanıcının verilerine sürekli erişimi sürdürmek için yenileme jetonlarını kullanır. Yenileme jetonları, eski erişim jetonunun süresi dolduğunda istemci tarafından yetkilendirme sunucusundan kısa ömürlü bir erişim jetonu istemek için kullanılan, uzun ömürlü jetonlardır. Bu işlem, kullanıcı etkileşimi olmadan gerçekleştirilir.
Yenileme jetonu almak için önce uygulamanızdaki yetkilendirme adımında "offline access" (çevrimdışı erişim) isteyerek bir yetkilendirme kodu almanız, ardından da yetkilendirme kodunu sunucunuzda yenileme jetonuyla değiştirmeniz gerekir. Yeni erişim jetonları almak için tekrar tekrar kullanılabildiklerinden, uzun ömürlü yenileme jetonlarını sunucunuzda güvenli bir şekilde saklamanız çok önemlidir. Bu nedenle, güvenlik endişeleri nedeniyle yenileme jetonlarının cihazda depolanması kesinlikle önerilmez. Bunun yerine, erişim jetonu için değişimin gerçekleştiği uygulamanın arka uç sunucularında depolanmalıdır.
Yetkilendirme kodu uygulamanızın arka uç sunucusuna gönderildikten sonra, hesap yetkilendirme kılavuzundaki adımları uygulayarak sunucuda kısa ömürlü bir erişim jetonu ve uzun ömürlü bir yenileme jetonu ile değiştirebilirsiniz. Bu alışveriş yalnızca uygulamanızın arka ucunda gerçekleşmelidir.
Kotlin
// Ask for offline access during the first authorization request
val authorizationRequest = AuthorizationRequest.builder()
.setRequestedScopes(requestedScopes)
.requestOfflineAccess(serverClientId)
.build()
Identity.getAuthorizationClient(activity)
.authorize(authorizationRequest)
.addOnSuccessListener { authorizationResult ->
startAuthorizationIntent.launchIntentSenderRequest.Builder(
pendingIntent!!.intentSender
).build()
}
.addOnFailureListener { e -> Log.e(TAG, "Failed to authorize", e) }
Java
// Ask for offline access during the first authorization request
AuthorizationRequest authorizationRequest = AuthorizationRequest.builder()
.setRequestedScopes(requestedScopes)
.requestOfflineAccess(serverClientId)
.build();
Identity.getAuthorizationClient(getContext())
.authorize(authorizationRequest)
.addOnSuccessListener(authorizationResult -> {
startAuthorizationIntent.launch(
new IntentSenderRequest.Builder(
authorizationResult.getPendingIntent().getIntentSender()
).build()
);
})
.addOnFailureListener(e -> Log.e(TAG, "Failed to authorize"));
Aşağıdaki snippet, yetkilendirmenin bir parçadan başlatıldığını varsayar.
Kotlin
private lateinit var startAuthorizationIntent: ActivityResultLauncher<IntentSenderRequest>
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
// ...
startAuthorizationIntent =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->
try {
val authorizationResult = Identity.getAuthorizationClient(requireContext())
.getAuthorizationResultFromIntent(activityResult.data)
// short-lived access token
accessToken = authorizationResult.accessToken
// store the authorization code used for getting a refresh token safely to your app's backend server
val authCode: String = authorizationResult.serverAuthCode
storeAuthCodeSafely(authCode)
} catch (e: ApiException) {
// log exception
}
}
}
Java
private ActivityResultLauncher<IntentSenderRequest> startAuthorizationIntent;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// ...
startAuthorizationIntent =
registerForActivityResult(
new ActivityResultContracts.StartIntentSenderForResult(),
activityResult -> {
try {
AuthorizationResult authorizationResult =
Identity.getAuthorizationClient(requireActivity())
.getAuthorizationResultFromIntent(activityResult.getData());
// short-lived access token
accessToken = authorizationResult.getAccessToken();
// store the authorization code used for getting a refresh token safely to your app's backend server
String authCode = authorizationResult.getServerAuthCode()
storeAuthCodeSafely(authCode);
} catch (ApiException e) {
// log exception
}
});
}