Logowanie do połączonego konta na Androida

Logowanie na powiązane konta umożliwia logowanie się jednym kliknięciem w Google dla użytkowników, którzy mają już konto Google połączone z Twoją usługą. Zwiększa to wygodę użytkowników, ponieważ mogą oni logować się jednym kliknięciem bez konieczności ponownego wpisywania nazwy użytkownika i hasła. Zmniejsza to także ryzyko tworzenia duplikatów kont w usłudze.

Łączenie kont jest dostępne w ramach logowania jednym dotknięciem na urządzeniu z Androidem. Oznacza to, że nie musisz importować osobnej biblioteki, jeśli Twoja aplikacja ma już włączoną funkcję jednego kliknięcia.

Z tego dokumentu dowiesz się, jak zmodyfikować aplikację na Androida, aby obsługiwała logowanie za pomocą połączonego konta.

Jak to działa

  1. Zgadzasz się na wyświetlanie połączonych kont podczas logowania się jednym kliknięciem.
  2. Jeśli użytkownik jest zalogowany w Google i połączył swoje konto Google ze swoim kontem w usłudze, wyślemy Ci token tożsamości połączonego konta.
  3. Użytkownik zobaczy prośbę o zalogowanie się jednym kliknięciem z opcją zalogowania się w usłudze za pomocą połączonego konta.
  4. Jeśli użytkownik zdecyduje się przejść na połączone konto, zostanie on zwrócony do Twojej aplikacji. Odpowiednio do tokena wysłanego do Twojego serwera w kroku 2 rozpoznasz zalogowanego użytkownika.

Konfiguracja

Skonfiguruj środowisko programistyczne

Poznaj najnowsze usługi Google Play na hoście:

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

  2. Jeśli stan tych pakietów nie został zainstalowany, wybierz je i kliknij Zainstaluj pakiety.

Konfigurowanie aplikacji

  1. W pliku build.gradle na poziomie projektu uwzględnij repozytorium Maven Google i w sekcjach buildscript i allprojects.

    buildscript {
        repositories {
            google()
        }
    }
    
    allprojects {
        repositories {
            google()
        }
    }
    
  2. Dodaj zależności do interfejsu API „Połącz z Google” w pliku Gradle na poziomie aplikacji, który zwykle wynosi app/build.gradle:

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

Modyfikowanie aplikacji na Androida na potrzeby logowania na połączone konto

Po zakończeniu procesu logowania się na połączone konto identyfikator zostanie zwrócony do Twojej aplikacji. Integralność tokena tożsamości powinna zostać zweryfikowana przed zalogowaniem się użytkownika.

Poniższy przykładowy kod zawiera instrukcje pobierania, weryfikacji tokena identyfikatora i późniejszego logowania użytkownika.

  1. Utwórz aktywność, aby otrzymać wynik 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 prośby o zalogowanie

    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. Uruchomienie intencji oczekującego 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 identyfikatora

To verify that the token is valid, ensure that the following criteria are satisfied:

  • The ID token is properly signed by Google. Use Google's public keys (available in JWK or PEM format) to verify the token's signature. These keys are regularly rotated; examine the Cache-Control header in the response to determine when you should retrieve them again.
  • The value of aud in the ID token is equal to one of your app's client IDs. This check is necessary to prevent ID tokens issued to a malicious app being used to access data about the same user on your app's backend server.
  • The value of iss in the ID token is equal to accounts.google.com or https://accounts.google.com.
  • The expiry time (exp) of the ID token has not passed.
  • If you want to restrict access to only members of your G Suite domain, verify that the ID token has an hd claim that matches your G Suite domain name.

Rather than writing your own code to perform these verification steps, we strongly recommend using a Google API client library for your platform, or a general-purpose JWT library. For development and debugging, you can call our tokeninfo validation endpoint.

Korzystanie z biblioteki klienta Google API

Zaleca się użycie biblioteki klienta interfejsu API Google Java w celu 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, deklarację aud, roszczenie iss i exp.

Jeśli chcesz ograniczyć dostęp tylko do użytkowników domeny G Suite, sprawdź też roszczenie hd, sprawdzając nazwę domeny zwróconej metodą Payload.getHostedDomain().

Calling the tokeninfo endpoint

An easy way to validate an ID token signature for debugging is to use the tokeninfo endpoint. Calling this endpoint involves an additional network request that does most of the validation for you while you test proper validation and payload extraction in your own code. It is not suitable for use in production code as requests may be throttled or otherwise subject to intermittent errors.

To validate an ID token using the tokeninfo endpoint, make an HTTPS POST or GET request to the endpoint, and pass your ID token in the id_token parameter. For example, to validate the token "XYZ123", make the following GET request:

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

If the token is properly signed and the iss and exp claims have the expected values, you will get a HTTP 200 response, where the body contains the JSON-formatted ID token claims. Here's an example response:

{
 // 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"
}

If you are a G Suite customer, you might also be interested in the hd claim, which indicates the hosted domain of the user. This can be used to restrict access to a resource to only members of certain domains. The absence of this claim indicates that the user does not belong to a G Suite hosted domain.