Logowanie na połączone konto (Android)

Logowanie na połączone konto włącza funkcję logowania się przez Google jednym dotknięciem w przypadku użytkowników, którzy mają już połączone konta Google z Twoją usługą. Zwiększa to wygodę użytkowników, ponieważ mogą logować się jednym kliknięciem bez konieczności ponownego wpisywania nazwy użytkownika i hasła. Zmniejsza to także szanse na utworzenie zduplikowanych kont przez użytkowników w Twojej usłudze.

Na urządzeniach z Androidem logowanie na powiązane konto jest możliwe w ramach logowania jednym dotknięciem. Oznacza to, że nie musisz importować osobnej biblioteki, jeśli Twoja aplikacja ma już włączoną funkcję jednego dotknięcia.

Z tego dokumentu dowiesz się, jak zmodyfikować aplikację na Androida pod kątem obsługi logowania na powiązane konto.

Jak to działa

  1. Wyrażasz zgodę na wyświetlanie połączonych kont podczas logowania się jednym dotknięciem.
  2. Jeśli użytkownik jest zalogowany w Google i połączył swoje konto Google ze swoim kontem w Twojej usłudze, dla połączonego konta zostanie zwrócony token identyfikatora.
  3. Użytkownik widzi prośbę o zalogowanie się jednym dotknięciem i może zalogować się w Twojej usłudze za pomocą połączonego konta.
  4. Jeśli użytkownik zdecyduje się kontynuować korzystanie z połączonego konta, token identyfikatora użytkownika zostanie zwrócony do Twojej aplikacji. Porównujesz go z tokenem wysłanym do Twojego serwera w kroku 2, aby zidentyfikować zalogowanego użytkownika.

Konfiguracja

Konfigurowanie środowiska programistycznego

Pobierz najnowsze Usługi Google Play na hosta dewelopera:

  1. Otwórz Menedżera pakietów SDK na Androida.
  1. W sekcji Narzędzia SDK znajdź Usługi Google Play.

  2. Jeśli pakiety te mają stan inny niż Zainstalowane, wybierz je i kliknij Zainstaluj pakiety.

Konfiguracja aplikacji

  1. W sekcji buildscript i allprojects pliku build.gradle na poziomie projektu dodaj repozytorium Google Maven.

    buildscript {
        repositories {
            google()
        }
    }
    
    allprojects {
        repositories {
            google()
        }
    }
    
  2. Dodaj zależności interfejsu API „Link with Google” do pliku Gradle na poziomie modułu. Zwykle ma on postać app/build.gradle:

    dependencies {
      implementation 'com.google.android.gms:play-services-auth:21.0.0'
    }
    

Zmodyfikuj aplikację na Androida, aby obsługiwała logowanie na połączonym koncie

Na końcu procesu logowania połączonego konta do aplikacji jest zwracany token identyfikatora. Integralność tokena identyfikatora należy sprawdzić przed zalogowaniem użytkownika.

Poniższy przykładowy kod zawiera szczegółowe instrukcje, jak pobrać, zweryfikować token identyfikatora, a następnie zalogować użytkownika.

  1. Utwórz działanie, aby otrzymać wynik intencji logowania

    Kotlin

      private val activityResultLauncher = registerForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()) { result ->
        if (result.resultCode == RESULT_OK) {
          try {
            val signInCredentials = Identity.signInClient(this)
                                    .signInCredentialFromIntent(result.data)
            // Review the Verify the integrity of the ID token section for
            // details on how to verify the ID token
            verifyIdToken(signInCredential.googleIdToken)
          } catch (e: ApiException) {
            Log.e(TAG, "Sign-in failed with error code:", e)
          }
        } else {
          Log.e(TAG, "Sign-in failed")
        }
      }
    

    Java

      private final ActivityResultLauncher<IntentSenderResult>
        activityResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartIntentSenderForResult(),
        result -> {
        If (result.getResultCode() == RESULT_OK) {
            try {
              SignInCredential signInCredential = Identity.getSignInClient(this)
                             .getSignInCredentialFromIntent(result.getData());
              verifyIdToken(signInCredential.getGoogleIdToken());
            } catch (e: ApiException ) {
              Log.e(TAG, "Sign-in failed with error:", e)
            }
        } else {
            Log.e(TAG, "Sign-in failed")
        }
    });
    
  2. Tworzenie żądania logowania

    Kotlin

    private val tokenRequestOptions =
    GoogleIdTokenRequestOptions.Builder()
      .supported(true)
      // Your server's client ID, not your Android client ID.
      .serverClientId(getString("your-server-client-id")
      .filterByAuthorizedAccounts(true)
      .associateLinkedAccounts("service-id-of-and-defined-by-developer",
                               scopes)
      .build()
    

    Java

     private final GoogleIdTokenRequestOptions tokenRequestOptions =
         GoogleIdTokenRequestOptions.Builder()
      .setSupported(true)
      .setServerClientId("your-service-client-id")
      .setFilterByAuthorizedAccounts(true)
      .associateLinkedAccounts("service-id-of-and-defined-by-developer",
                                scopes)
      .build()
    
  3. Uruchamianie intencji oczekującej na zalogowanie

    Kotlin

     Identity.signInClient(this)
        .beginSignIn(
      BeginSignInRequest.Builder()
        .googleIdTokenRequestOptions(tokenRequestOptions)
      .build())
        .addOnSuccessListener{result ->
          activityResultLauncher.launch(result.pendingIntent.intentSender)
      }
      .addOnFailureListener {e ->
        Log.e(TAG, "Sign-in failed because:", e)
      }
    

    Java

     Identity.getSignInClient(this)
      .beginSignIn(
        BeginSignInRequest.Builder()
          .setGoogleIdTokenRequestOptions(tokenRequestOptions)
          .build())
      .addOnSuccessListener(result -> {
        activityResultLauncher.launch(
            result.getPendingIntent().getIntentSender());
    })
    .addOnFailureListener(e -> {
      Log.e(TAG, "Sign-in failed because:", e);
    });
    

Sprawdzanie integralności tokena tożsamości

Aby sprawdzić, czy token jest prawidłowy, sprawdź, czy są spełnione te kryteria:

  • Token tożsamości jest prawidłowo podpisany przez Google. Do weryfikacji podpisu tokena użyj kluczy publicznych Google (dostępnych w formacie JWK lub PEM). Te klucze są regularnie poddawane rotacji. Sprawdź nagłówek Cache-Control w odpowiedzi, aby określić, kiedy należy je ponownie pobrać.
  • Wartość aud w tokenie identyfikatora jest równa jednemu z identyfikatorów klienta Twojej aplikacji. Ta weryfikacja jest konieczna, by zapobiec używaniu tokenów tożsamości wydanych do szkodliwej aplikacji do uzyskiwania dostępu do danych o tym samym użytkowniku na serwerze backendu aplikacji.
  • Wartość iss w tokenie identyfikatora jest równa accounts.google.com lub https://accounts.google.com.
  • Data ważności (exp) tokena identyfikatora jeszcze nie upłynął.
  • Aby sprawdzić, czy token identyfikatora reprezentuje konto organizacji w Google Workspace lub Cloud, możesz zapoznać się z deklaracją hd, która wskazuje hostowaną domenę użytkownika. Tej opcji należy używać, gdy ograniczasz dostęp do zasobu tylko do użytkowników z określonych domen. Brak takiego roszczenia oznacza, że konto nie należy do domeny hostowanej przez Google.

Zamiast pisać własny kod do wykonywania tych czynności weryfikacyjnych, zdecydowanie zalecamy użycie na platformie biblioteki klienta interfejsu API Google lub ogólnej biblioteki JWT. Na potrzeby programowania i debugowania możesz wywołać nasz punkt końcowy weryfikacji tokeninfo.

Używanie biblioteki klienta interfejsów API Google

Używanie biblioteki klienta interfejsu API Google w języku Java to zalecany sposób weryfikacji tokenów identyfikatorów Google w środowisku produkcyjnym.

Java

  import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
  import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
  import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

  ...

  GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
      // Specify the CLIENT_ID of the app that accesses the backend:
      .setAudience(Collections.singletonList(CLIENT_ID))
      // Or, if multiple clients access the backend:
      //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
      .build();

  // (Receive idTokenString by HTTPS POST)

  GoogleIdToken idToken = verifier.verify(idTokenString);
  if (idToken != null) {
    Payload payload = idToken.getPayload();

    // Print user identifier
    String userId = payload.getSubject();
    System.out.println("User ID: " + userId);

    // Get profile information from payload
    String email = payload.getEmail();
    boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
    String name = (String) payload.get("name");
    String pictureUrl = (String) payload.get("picture");
    String locale = (String) payload.get("locale");
    String familyName = (String) payload.get("family_name");
    String givenName = (String) payload.get("given_name");

    // Use or store profile information
    // ...

  } else {
    System.out.println("Invalid ID token.");
  }

Metoda GoogleIdTokenVerifier.verify() weryfikuje podpis JWT, deklaracje aud, iss i ichexp.

Jeśli chcesz sprawdzić, czy token identyfikatora reprezentuje konto organizacji w Google Workspace lub Cloud, możesz zweryfikować deklarację hd, sprawdzając nazwę domeny zwracaną przy użyciu metody Payload.getHostedDomain().

Wywoływanie punktu końcowego tokeninfo

Łatwym sposobem na zweryfikowanie podpisu tokena identyfikatora na potrzeby debugowania jest użycie punktu końcowego tokeninfo. Wywołanie tego punktu końcowego obejmuje dodatkowe żądanie sieciowe, które wykonuje większość weryfikacji za Ciebie, a jednocześnie testujesz prawidłową weryfikację i wyodrębnianie ładunków we własnym kodzie. Nie można go stosować w kodzie produkcyjnym, ponieważ żądania mogą być ograniczane lub w inny sposób powodować przejściowe błędy.

Aby zweryfikować token identyfikatora za pomocą punktu końcowego tokeninfo, wyślij żądanie HTTPS POST lub GET do punktu końcowego i przekaż token identyfikatora w parametrze id_token. Aby na przykład zweryfikować token „XYZ123”, wyślij następujące żądanie GET:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

Jeśli token jest prawidłowo podpisany, a żądania iss i exp mają oczekiwane wartości, otrzymasz odpowiedź HTTP 200, w której treść zawiera żądania tokena identyfikatora w formacie JSON. Przykładowa odpowiedź:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

Aby sprawdzić, czy token identyfikatora reprezentuje konto Google Workspace, możesz zapoznać się z deklaracją hd, która wskazuje domenę hostowaną użytkownika. Tej opcji należy używać na potrzeby ograniczania dostępu do zasobu tylko osobom z określonych domen. Brak takiego stwierdzenia oznacza, że konto nie należy do domeny hostowanej w Google Workspace.