Google उपयोगकर्ता के डेटा को ऐक्सेस करने की अनुमति देना

पुष्टि करने से यह पता चलता है कि कोई व्यक्ति कौन है. इसे आम तौर पर, उपयोगकर्ता का साइन-अप या साइन-इन करना कहा जाता है. अनुमति देने की प्रक्रिया में, डेटा या संसाधनों को ऐक्सेस करने की अनुमति दी जाती है या उसे अस्वीकार किया जाता है. उदाहरण के लिए, आपका ऐप्लिकेशन उपयोगकर्ता के Google Drive को ऐक्सेस करने के लिए, उसकी सहमति का अनुरोध करता है.

ऐप्लिकेशन की ज़रूरतों के आधार पर, पुष्टि करने और अनुमति देने के लिए दो अलग-अलग फ़्लो होने चाहिए.

अगर आपके ऐप्लिकेशन में ऐसी सुविधाएं हैं जो Google API के डेटा का इस्तेमाल कर सकती हैं, लेकिन ऐप्लिकेशन की मुख्य सुविधाओं के तौर पर इनकी ज़रूरत नहीं है, तो आपको अपने ऐप्लिकेशन को इस तरह से डिज़ाइन करना चाहिए कि जब एपीआई का डेटा ऐक्सेस न किया जा सके, तब भी वह ठीक से काम कर सके. उदाहरण के लिए, जब उपयोगकर्ता ने Drive का ऐक्सेस नहीं दिया हो, तब हाल ही में सेव की गई फ़ाइलों की सूची को छिपाया जा सकता है.

आपको सिर्फ़ उन स्कोप के ऐक्सेस का अनुरोध करना चाहिए जिनकी मदद से Google API को ऐक्सेस किया जा सकता है. ऐसा तब करें, जब उपयोगकर्ता कोई ऐसी कार्रवाई करता है जिसके लिए किसी खास एपीआई को ऐक्सेस करना ज़रूरी हो. उदाहरण के लिए, जब भी कोई उपयोगकर्ता "Drive में सेव करें" बटन पर टैप करे, तब आपको उपयोगकर्ता के Drive को ऐक्सेस करने की अनुमति का अनुरोध करना चाहिए.

अनुमति देने की प्रोसेस को पुष्टि करने की प्रोसेस से अलग करके, नए उपयोगकर्ताओं को ज़्यादा जानकारी देने से बचा जा सकता है. साथ ही, उपयोगकर्ताओं को यह भी बताया जा सकता है कि उनसे कुछ अनुमतियां क्यों मांगी जा रही हैं.

हमारा सुझाव है कि पुष्टि करने के लिए, Credential Manager API का इस्तेमाल करें. Google के पास सेव किए गए उपयोगकर्ता के डेटा को ऐक्सेस करने वाली कार्रवाइयों को अनुमति देने के लिए, हमारा सुझाव है कि आप AuthorizationClient का इस्तेमाल करें.

अपना प्रोजेक्ट सेट अप करना

  1. में अपना प्रोजेक्ट खोलें. अगर आपके पास पहले से कोई प्रोजेक्ट नहीं है, तो एक प्रोजेक्ट बनाएं.
  2. पर जाकर, पक्का करें कि दी गई सारी जानकारी पूरी और सटीक हो.
    1. पक्का करें कि आपके ऐप्लिकेशन के लिए सही ऐप्लिकेशन का नाम, ऐप्लिकेशन का लोगो, और ऐप्लिकेशन का होम पेज असाइन किया गया हो. ये वैल्यू, उपयोगकर्ताओं को साइन अप करने के दौरान 'Google से साइन इन करें' सुविधा के लिए सहमति वाली स्क्रीन पर और तीसरे पक्ष के ऐप्लिकेशन और सेवाओं वाली स्क्रीन पर दिखेंगी.
    2. पक्का करें कि आपने अपने ऐप्लिकेशन की निजता नीति और सेवा की शर्तों के यूआरएल दिए हों.
  3. में जाकर, अपने ऐप्लिकेशन के लिए Android क्लाइंट आईडी बनाएं. ऐसा तब करें, जब आपके पास पहले से कोई आईडी न हो. आपको अपने ऐप्लिकेशन के पैकेज का नाम और SHA-1 हस्ताक्षर बताना होगा.
    1. पर जाएं.
    2. क्लाइंट खाता बनाएं पर क्लिक करें.
    3. Android ऐप्लिकेशन टाइप चुनें.
  4. अगर आपने अब तक नया "वेब ऐप्लिकेशन" क्लाइंट आईडी नहीं बनाया है, तो में जाकर, नया क्लाइंट आईडी बनाएं. फ़िलहाल, "अनुमति वाले JavaScript ऑरिजिन" और "अनुमति वाले रीडायरेक्ट यूआरआई" फ़ील्ड को अनदेखा किया जा सकता है. इस क्लाइंट आईडी का इस्तेमाल, आपके बैकएंड सर्वर की पहचान करने के लिए किया जाएगा. ऐसा तब होगा, जब वह Google की पुष्टि करने वाली सेवाओं से कम्यूनिकेट करेगा.
    1. पर जाएं.
    2. क्लाइंट खाता बनाएं पर क्लिक करें.
    3. वेब ऐप्लिकेशन टाइप चुनें.

डिपेंडेंसी का एलान करना

अपने मॉड्यूल की build.gradle फ़ाइल में, Google Identity Services लाइब्रेरी के नए वर्शन का इस्तेमाल करके डिपेंडेंसी का एलान करें.

dependencies {
  // ... other dependencies

  implementation "com.google.android.gms:play-services-auth:21.4.0"
}

उपयोगकर्ता की कार्रवाइयों के लिए ज़रूरी अनुमतियों का अनुरोध करना

जब भी कोई उपयोगकर्ता ऐसी कार्रवाई करता है जिसके लिए अतिरिक्त स्कोप की ज़रूरत होती है, तब AuthorizationClient.authorize() को कॉल करें. उदाहरण के लिए, अगर कोई उपयोगकर्ता ऐसी कार्रवाई करता है जिसके लिए, उसके Drive ऐप्लिकेशन के स्टोरेज का ऐक्सेस ज़रूरी है, तो यह तरीका अपनाएं:

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 को तय करते समय, जवाब को इस स्निपेट में दिखाए गए तरीके से हैंडल करें. इसमें हम मानते हैं कि यह काम किसी फ़्रैगमेंट में किया गया है. यह कोड यह जांच करता है कि ज़रूरी अनुमतियां दी गई हैं या नहीं. इसके बाद, यह उपयोगकर्ता की कार्रवाई को पूरा करता है.

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 को ऐक्सेस किया जा रहा है, तो AuthorizationResult से getServerAuthCode() तरीके को कॉल करें. इससे आपको एक ऑथराइज़ेशन कोड मिलेगा. इस कोड को अपने बैकएंड पर भेजें, ताकि इसे ऐक्सेस और रीफ़्रेश टोकन के बदले में बदला जा सके. ज़्यादा जानने के लिए, उपयोगकर्ता के डेटा का ऐक्सेस बनाए रखना लेख पढ़ें.

उपयोगकर्ता के डेटा या संसाधनों के लिए अनुमतियां रद्द करना

पहले दिए गए ऐक्सेस को रद्द करने के लिए, AuthorizationClient.revokeAccess() पर कॉल करें. उदाहरण के लिए, अगर कोई उपयोगकर्ता आपके ऐप्लिकेशन से अपना खाता हटा रहा है और आपके ऐप्लिकेशन को पहले DriveScopes.DRIVE_FILE का ऐक्सेस दिया गया था, तो ऐक्सेस रद्द करने के लिए इस कोड का इस्तेमाल करें:

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));

टोकन कैश मेमोरी मिटाना

OAuth ऐक्सेस टोकन को सर्वर से मिलने के बाद, स्थानीय तौर पर कैश मेमोरी में सेव किया जाता है. इससे ऐक्सेस करने की प्रोसेस तेज़ हो जाती है और नेटवर्क कॉल कम हो जाते हैं. इन टोकन की समयसीमा खत्म होने पर, ये कैश मेमोरी से अपने-आप मिट जाते हैं. हालांकि, ये टोकन अन्य वजहों से भी अमान्य हो सकते हैं. अगर आपको टोकन का इस्तेमाल करते समय IllegalStateException मिलता है, तो लोकल कैश मेमोरी मिटाएं. इससे यह पक्का किया जा सकेगा कि ऐक्सेस टोकन के लिए अगला ऑथराइज़ेशन अनुरोध, OAuth सर्वर को भेजा जाए. नीचे दिए गए स्निपेट से, लोकल कैश मेमोरी से invalidAccessToken को हटाया जाता है:

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));

अनुमति देने के दौरान उपयोगकर्ता की जानकारी पाना

अनुमति देने वाले जवाब में, इस्तेमाल किए गए उपयोगकर्ता खाते के बारे में कोई जानकारी शामिल नहीं है. जवाब में सिर्फ़ अनुरोध किए गए स्कोप के लिए टोकन शामिल है. उदाहरण के लिए, किसी उपयोगकर्ता के Google Drive को ऐक्सेस करने के लिए ऐक्सेस टोकन पाने के जवाब में, उस खाते की पहचान ज़ाहिर नहीं की जाती जिसे उपयोगकर्ता ने चुना था. भले ही, इसका इस्तेमाल उपयोगकर्ता के Drive में मौजूद फ़ाइलों को ऐक्सेस करने के लिए किया जा सकता हो. उपयोगकर्ता का नाम या ईमेल पता जैसी जानकारी पाने के लिए, आपके पास ये विकल्प हैं:

  • अनुमति मांगने से पहले, उपयोगकर्ता को Credential Manager API का इस्तेमाल करके, उसके Google खाते से साइन इन कराएं. क्रेडेंशियल मैनेजर से मिले पुष्टि करने के जवाब में, उपयोगकर्ता की जानकारी शामिल होती है. जैसे, ईमेल पता. साथ ही, यह ऐप्लिकेशन के डिफ़ॉल्ट खाते को चुने गए खाते पर सेट करता है. अगर ज़रूरी हो, तो अपने ऐप्लिकेशन में इस खाते को ट्रैक किया जा सकता है. इसके बाद, अनुमति देने के अनुरोध में खाते को डिफ़ॉल्ट के तौर पर इस्तेमाल किया जाता है. साथ ही, अनुमति देने के फ़्लो में खाता चुनने के चरण को छोड़ दिया जाता है. अनुमति देने के लिए किसी दूसरे खाते का इस्तेमाल करने के बारे में जानने के लिए, गैर-डिफ़ॉल्ट खाते से अनुमति लेना लेख पढ़ें.

  • अनुमति के अपने अनुरोध में, आपको जिन स्कोप की ज़रूरत है उनके अलावा (उदाहरण के लिए, Drive scope), userinfo, profile, और openid स्कोप के लिए भी अनुरोध करें. ऐक्सेस टोकन मिलने के बाद, उपयोगकर्ता की जानकारी पाने के लिए, अपनी पसंद की एचटीटीपी लाइब्रेरी का इस्तेमाल करके, GETOAuth userinfo एंडपॉइंट (https://www.googleapis.com/oauth2/v3/userinfo) को एचटीटीपी अनुरोध करें. साथ ही, हेडर में वह ऐक्सेस टोकन शामिल करें जो आपको मिला था. यह curl कमांड के बराबर है:

    curl -X GET \ "https://www.googleapis.com/oauth2/v1/userinfo?alt=json" \ -H "Authorization: Bearer $TOKEN"
    

    जवाब, UserInfo है. यह उन स्कोप तक सीमित है जिनके लिए अनुरोध किया गया था. इसे JSON फ़ॉर्मैट में बनाया गया है.

डिफ़ॉल्ट खाते के अलावा किसी दूसरे खाते से अनुमति लेना

अगर पुष्टि करने के लिए Credential Manager का इस्तेमाल किया जाता है और AuthorizationClient.authorize() चलाया जाता है, तो आपके ऐप्लिकेशन का डिफ़ॉल्ट खाता, उपयोगकर्ता के चुने गए खाते के तौर पर सेट हो जाता है. इसका मतलब है कि पुष्टि के लिए किए जाने वाले सभी कॉल के लिए, इस डिफ़ॉल्ट खाते का इस्तेमाल किया जाता है. खाता चुनने का विकल्प दिखाने के लिए, क्रेडेंशियल मैनेजर के clearCredentialState() एपीआई का इस्तेमाल करके, उपयोगकर्ता को ऐप्लिकेशन से साइन आउट करें.

उपयोगकर्ता के डेटा का ऐक्सेस बनाए रखना

अगर आपको अपने ऐप्लिकेशन से उपयोगकर्ता के डेटा को ऐक्सेस करना है, तो AuthorizationClient.authorize() को एक बार कॉल करें. इसके बाद के सेशन में और जब तक उपयोगकर्ता दी गई अनुमतियों को नहीं हटाता, तब तक अपने लक्ष्यों को पूरा करने के लिए, उसी तरीके को कॉल करें. इससे आपको बिना किसी उपयोगकर्ता इंटरैक्शन के ऐक्सेस टोकन मिल जाएगा. अगर आपको बैकएंड सर्वर से, ऑफ़लाइन मोड में उपयोगकर्ता के डेटा को ऐक्सेस करना है, तो आपको "रीफ़्रेश टोकन" नाम के किसी दूसरे टोकन का अनुरोध करना होगा.

ऐक्सेस टोकन को जान-बूझकर कम समय के लिए डिज़ाइन किया गया है. इनकी अवधि एक घंटे की होती है. अगर ऐक्सेस टोकन को इंटरसेप्ट किया जाता है या उसके साथ छेड़छाड़ की जाती है, तो उसकी सीमित वैधता अवधि की वजह से, उसके गलत इस्तेमाल की आशंका कम हो जाती है. समयसीमा खत्म होने के बाद, टोकन अमान्य हो जाता है. साथ ही, इसका इस्तेमाल करने की किसी भी कोशिश को संसाधन सर्वर अस्वीकार कर देता है. ऐक्सेस टोकन की समयसीमा कम होती है. इसलिए, सर्वर रीफ़्रेश टोकन का इस्तेमाल करते हैं, ताकि उपयोगकर्ता के डेटा का ऐक्सेस बना रहे. रीफ़्रेश टोकन, लंबे समय तक इस्तेमाल किए जा सकने वाले टोकन होते हैं. इनका इस्तेमाल क्लाइंट, ऑथराइज़ेशन सर्वर से कम समय के लिए ऐक्सेस टोकन का अनुरोध करने के लिए करता है. ऐसा तब किया जाता है, जब पुराना ऐक्सेस टोकन खत्म हो जाता है और उपयोगकर्ता को कोई कार्रवाई नहीं करनी पड़ती.

रीफ़्रेश टोकन पाने के लिए, आपको सबसे पहले अपने ऐप्लिकेशन में पुष्टि करने के चरण के दौरान, ऑथराइज़ेशन कोड पाना होगा. इसके लिए, "ऑफ़लाइन ऐक्सेस" का अनुरोध करें. इसके बाद, अपने सर्वर पर ऑथराइज़ेशन कोड को रीफ़्रेश टोकन से बदलें. लंबे समय तक चलने वाले रिफ़्रेश टोकन को अपने सर्वर पर सुरक्षित तरीके से सेव करना ज़रूरी है. ऐसा इसलिए, क्योंकि इनका इस्तेमाल बार-बार नए ऐक्सेस टोकन पाने के लिए किया जा सकता है. इसलिए, सुरक्षा से जुड़ी समस्याओं की वजह से, डिवाइस पर रीफ़्रेश टोकन सेव न करने का सुझाव दिया जाता है. इसके बजाय, इन्हें ऐप्लिकेशन के बैकएंड सर्वर में सेव किया जाना चाहिए. यहां ऐक्सेस टोकन के लिए एक्सचेंज होता है.

आपके ऐप्लिकेशन के बैकएंड सर्वर को ऑथराइज़ेशन कोड भेजे जाने के बाद, सर्वर पर कम समय तक चलने वाले ऐक्सेस टोकन और लंबे समय तक चलने वाले रीफ़्रेश टोकन के लिए, इसे बदला जा सकता है. इसके लिए, खाता ऑथराइज़ेशन गाइड में दिए गए चरणों का पालन करें. यह एक्सचेंज सिर्फ़ आपके ऐप्लिकेशन के बैकएंड में होना चाहिए.

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"));

इस स्निपेट में यह माना गया है कि अनुमति देने की प्रोसेस, फ़्रैगमेंट से शुरू की गई है.

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
                }
            });
}