저장된 사용자 인증 정보로 사용자 로그인 처리

원탭 로그인 클라이언트를 사용하여 사용자에게 이전에 앱에 로그인할 때 사용한 사용자 인증 정보 중 하나 이러한 사용자 인증 정보는 Google 계정 또는 사용자 이름과 비밀번호의 조합일 수 있습니다. Chrome, Android 자동 완성 또는 Smart Lock을 사용하여 Google에 저장한 항목 비밀번호.

원탭 로그인 UI

사용자 인증 정보를 성공적으로 가져오면 이를 사용하여 원활하게 사용자를 앱에 로그인하도록 합니다.

사용자가 사용자 인증 정보를 저장하지 않은 경우 UI가 표시되지 않고 일반적인 로그아웃 환경을 제공합니다.

원탭 로그인은 어디에서 사용해야 하나요?

앱에 사용자 로그인이 필요한 경우 로그인 시 원탭 UI를 표시합니다. 화면 이는 이미 'Google 계정으로 로그인'이 있는 경우에도 유용할 수 있습니다. 버튼: 사용자 인증 정보만 표시하도록 원탭 UI를 구성할 수 있기 때문에 드물게 로그인했던 사용자에게 알림이 될 수 있습니다. 이전에 로그인했던 방식으로 로그인하도록 하여 실수로 인한 피해를 방지할 수 있습니다 .

앱에서 로그인이 선택 사항인 경우 어떤 기기에서든 원탭 로그인을 사용해 보세요. 개선된 환경을 경험할 수 있습니다. 예를 들어 사용자가 로그아웃한 상태에서 앱으로 콘텐츠를 탐색하지만 댓글을 게시하거나 콘텐츠를 추가할 수만 있음 장바구니에 상품을 추가할 수 있다고 가정해 보겠습니다. 원탭 로그인

로그인 선택 앱은 로그인 화면에서도 원탭 로그인을 사용해야 합니다. 사용할 수 없습니다.

시작하기 전에

  • 다음에 설명된 대로 Google API 콘솔 프로젝트 및 Android 프로젝트를 설정합니다. 원탭 로그인 시작하기
  • 비밀번호 기반 로그인을 지원하는 경우 자동 완성 (또는 비밀번호 대용 Smart Lock 사용)을 통해 사용자가 비밀번호를 저장할 수 있습니다. 로그인 후 비밀번호 사용자 인증 정보가 표시됩니다.

1. 원탭 로그인 클라이언트 구성

저장된 로그인 계정으로 사용자가 로그인하도록 원탭 로그인 클라이언트를 구성할 수 있습니다. 액세스할 수 있습니다. (두 가지를 모두 지원하는 것이 좋으며 신규 사용자를 위한 원탭 계정 생성 및 자동 또는 원탭 로그인 사용 설정 가능한 한 많은 재사용자들에게 혜택을 제공할 수 있습니다.)

앱에서 비밀번호 기반 로그인을 사용하는 경우 setPasswordRequestOptions()을(를) 사용하여 다음을 수행합니다. 사용자 인증 정보 요청을 사용 설정합니다

앱에서 Google 로그인을 사용하는 경우 setGoogleIdTokenRequestOptions()를 사용하여 다음을 할 수 있습니다. Google ID 토큰 요청을 사용 설정 및 구성합니다.

  • 서버 클라이언트 ID를 Google API에서 만든 ID로 설정합니다. 콘솔을 참조하세요. 이 ID는 서버의 클라이언트 ID이며 Android 클라이언트 ID입니다.

  • 승인된 계정으로 필터링하도록 클라이언트를 구성합니다. 이 기능을 사용 설정하면 옵션을 선택하면 원탭 클라이언트에서 사용자에게 이전에 이미 사용한 적이 있는 Google 계정 이렇게 하면 사용자가 계정이 있는지 또는 계정이 어떤 것인지 확실하지 않을 때 사용자가 실수로 새 Google 계정을 만드는 것을 방지하며 계정을 만들 수 있습니다.

  • 가능한 경우 사용자가 자동으로 로그인하도록 하려면 이 기능을 사용 설정합니다. setAutoSelectEnabled()를 사용합니다. 자동 로그인은 다음 기준이 충족됩니다.

    • 앱에 저장된 사용자의 사용자 인증 정보가 정확히 한 개입니다. 즉, 저장된 비밀번호 또는 저장된 Google 계정이 한 개입니다.
    • 사용자가 Google 계정 설정에서 자동 로그인을 사용 중지하지 않았습니다.
  • 선택사항이지만 nonce를 사용하여 로그인 보안을 강화하고 재전송 공격을 피할 수 있습니다. 사용 setNonce 를 사용하여 각 요청에 nonce를 포함합니다. SafetyNet 보기 nonce 가져오기 섹션을 참조하세요.

자바

public class YourActivity extends AppCompatActivity {
  // ...

  private SignInClient oneTapClient;
  private BeginSignInRequest signInRequest;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState,
                       @Nullable PersistableBundle persistentState) {
      super.onCreate(savedInstanceState, persistentState);

      oneTapClient = Identity.getSignInClient(this);
      signInRequest = BeginSignInRequest.builder()
              .setPasswordRequestOptions(PasswordRequestOptions.builder()
                      .setSupported(true)
                      .build())
              .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder()
                      .setSupported(true)
                      // Your server's client ID, not your Android client ID.
                      .setServerClientId(getString(R.string.default_web_client_id))
                      // Only show accounts previously used to sign in.
                      .setFilterByAuthorizedAccounts(true)
                      .build())
              // Automatically sign in when exactly one credential is retrieved.
              .setAutoSelectEnabled(true)
              .build();
      // ...
  }
  // ...
}

Kotlin

class YourActivity : AppCompatActivity() {
    // ...

    private lateinit var oneTapClient: SignInClient
    private lateinit var signInRequest: BeginSignInRequest

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        oneTapClient = Identity.getSignInClient(this)
        signInRequest = BeginSignInRequest.builder()
            .setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder()
                .setSupported(true)
                .build())
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.your_web_client_id))
                    // Only show accounts previously used to sign in.
                    .setFilterByAuthorizedAccounts(true)
                    .build())
            // Automatically sign in when exactly one credential is retrieved.
            .setAutoSelectEnabled(true)
            .build()
        // ...
    }
    // ...
}

2. 로그인한 사용자 확인

로그인한 사용자 또는 로그아웃한 사용자가 활동을 사용할 수 있는 경우 다음을 확인하세요. 원탭 로그인 UI를 표시하기 전에 사용자의 상태를 확인합니다.

또한 사용자가 이미 사용을 거부했는지도 추적해야 합니다. 원탭에 로그인하려면 메시지를 닫거나 메시지 외부를 탭하세요. 이렇게 하면 액티비티의 불리언 속성만큼 간단해야 합니다. 아래의 원탭 UI 표시 중지를 참고하세요.

3. 원탭 로그인 UI 표시

사용자가 로그인되어 있지 않고 원탭 로그인 사용을 아직 거부하지 않은 경우 클라이언트 객체의 beginSignIn() 메서드를 호출하고 리스너를 Task를 반환합니다. 일반적으로 앱은 활동의 onCreate() 메서드에서 이 작업을 실행합니다. 단일 액티비티 아키텍처를 사용할 때 또는 화면 전환 후에 렌더링을 수행할 수 있습니다.

사용자가 저장한 항목이 있으면 원탭 클라이언트는 성공 리스너를 호출합니다. 사용자 인증 정보를 제공합니다 성공 리스너에서 대기 중인 인텐트를 다음에서 가져옵니다. Task 결과를 가져와서 startIntentSenderForResult()에 전달하여 원탭 로그인 UI입니다.

사용자에게 저장된 사용자 인증 정보가 없는 경우 원탭 클라이언트는 실패 리스너입니다. 이 경우 별도의 조치가 필요하지 않습니다. 앱의 로그아웃 환경을 보여줍니다. 하지만 원탭을 지원하는 경우 원활하게 계정을 만들기 위해 여기에서 해당 절차를 시작할 수 있습니다. 경험해 볼 수 있습니다 탭 한 번으로 새 계정 만들기를 참조하세요.

자바

oneTapClient.beginSignIn(signUpRequest)
        .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
            @Override
            public void onSuccess(BeginSignInResult result) {
                try {
                    startIntentSenderForResult(
                            result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
                            null, 0, 0, 0);
                } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
                }
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // No saved credentials found. Launch the One Tap sign-up flow, or
                // do nothing and continue presenting the signed-out UI.
                Log.d(TAG, e.getLocalizedMessage());
            }
        });

Kotlin

oneTapClient.beginSignIn(signInRequest)
    .addOnSuccessListener(this) { result ->
        try {
            startIntentSenderForResult(
                result.pendingIntent.intentSender, REQ_ONE_TAP,
                null, 0, 0, 0, null)
        } catch (e: IntentSender.SendIntentException) {
            Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
        }
    }
    .addOnFailureListener(this) { e ->
        // No saved credentials found. Launch the One Tap sign-up flow, or
        // do nothing and continue presenting the signed-out UI.
        Log.d(TAG, e.localizedMessage)
    }

4. 사용자 응답 처리

원탭 로그인 메시지에 대한 사용자의 응답이 앱에 보고됩니다. Activity의 onActivityResult() 메서드 사용 사용자가 로그인을 선택하면 결과는 저장된 사용자 인증 정보입니다. 사용자가 로그인을 거부한 경우 원탭 UI를 닫거나 외부를 탭하면 결과가 코드 RESULT_CANCELED입니다. 앱은 두 가지 가능성을 모두 처리해야 합니다.

가져온 사용자 인증 정보로 로그인

사용자가 사용자 인증 정보를 앱과 공유하기로 선택한 경우 onActivityResult()에서 원탭 클라이언트의 getSignInCredentialFromIntent() 메서드를 사용하여 지도 가장자리에 패딩을 추가할 수 있습니다. 사용자 인증 정보에 null이 아닌 사용자가 Google 계정 사용자 인증 정보를 공유한 경우 googleIdToken 속성 앱 또는 사용자가 저장된 비밀번호를 공유한 경우 null이 아닌 password 속성

사용자 인증 정보를 사용하여 앱의 백엔드에 인증합니다.

  • 사용자 이름과 비밀번호 쌍을 가져온 경우 이를 사용하여 동일한 사용자가 수동으로 URL을 제공했다면 할 수 있는 방식으로 지정해야 합니다.
  • Google 계정 사용자 인증 정보를 가져온 경우 ID 토큰을 사용하여 인증합니다. 사용할 수 있습니다 재생 방지를 위해 nonce를 사용하도록 선택한 경우 백엔드 서버의 응답값을 확인합니다 자세한 내용은 ID 토큰을 사용하여 백엔드로 인증합니다.

자바

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data);
                  String idToken = credential.getGoogleIdToken();
                  String username = credential.getId();
                  String password = credential.getPassword();
                  if (idToken !=  null) {
                      // Got an ID token from Google. Use it to authenticate
                      // with your backend.
                      Log.d(TAG, "Got ID token.");
                  } else if (password != null) {
                      // Got a saved username and password. Use them to authenticate
                      // with your backend.
                      Log.d(TAG, "Got password.");
                  }
              } catch (ApiException e) {
                  // ...
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
             REQ_ONE_TAP -> {
                try {
                    val credential = oneTapClient.getSignInCredentialFromIntent(data)
                    val idToken = credential.googleIdToken
                    val username = credential.id
                    val password = credential.password
                    when {
                        idToken != null -> {
                            // Got an ID token from Google. Use it to authenticate
                            // with your backend.
                            Log.d(TAG, "Got ID token.")
                        }
                        password != null -> {
                            // Got a saved username and password. Use them to authenticate
                            // with your backend.
                            Log.d(TAG, "Got password.")
                        }
                        else -> {
                            // Shouldn't happen.
                            Log.d(TAG, "No ID token or password!")
                        }
                    }
                } catch (e: ApiException) {
                    // ...
                }
            }
        }
    }
    // ...
}

원탭 UI 표시 중지

사용자가 로그인을 거부한 경우 getSignInCredentialFromIntent() 호출 CommonStatusCodes.CANCELED 상태 코드와 함께 ApiException이 발생합니다. 이 경우 원탭 로그인 UI를 일시적으로 사용 중지하여 반복 메시지로 사용자를 귀찮게 하지 않을 수 있습니다 다음 예는 액티비티에서 속성을 설정하면 됩니다. 이 속성은 사용자에게 원탭 로그인을 제공합니다. 값을 저장해 두었다가 SharedPreferences 또는 다른 메서드를 사용하세요.

원탭 로그인 메시지에 자체 비율 제한을 구현하는 것이 중요합니다. 그렇게 하지 않고 사용자가 연속으로 여러 메시지를 취소하는 경우 원탭 클라이언트는 다음 24시간 동안 사용자에게 메시지를 표시하지 않습니다.

자바

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  // ...
              } catch (ApiException e) {
                  switch (e.getStatusCode()) {
                      case CommonStatusCodes.CANCELED:
                          Log.d(TAG, "One-tap dialog was closed.");
                          // Don't re-prompt the user.
                          showOneTapUI = false;
                          break;
                      case CommonStatusCodes.NETWORK_ERROR:
                          Log.d(TAG, "One-tap encountered a network error.");
                          // Try again or just ignore.
                          break;
                      default:
                          Log.d(TAG, "Couldn't get credential from result."
                                  + e.getLocalizedMessage());
                          break;
                  }
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
            REQ_ONE_TAP -> {
                try {
                    // ...
                } catch (e: ApiException) {
                    when (e.statusCode) {
                        CommonStatusCodes.CANCELED -> {
                            Log.d(TAG, "One-tap dialog was closed.")
                            // Don't re-prompt the user.
                            showOneTapUI = false
                        }
                        CommonStatusCodes.NETWORK_ERROR -> {
                            Log.d(TAG, "One-tap encountered a network error.")
                            // Try again or just ignore.
                        }
                        else -> {
                            Log.d(TAG, "Couldn't get credential from result." +
                                " (${e.localizedMessage})")
                        }
                    }
                }
            }
        }
    }
    // ...
}

5. 로그아웃 처리

사용자가 앱에서 로그아웃하면 원탭 클라이언트의 signOut() 메서드를 호출합니다. signOut()를 호출하면 사용자가 다시 로그인할 때까지 자동 로그인이 사용 중지됩니다.

자동 로그인을 사용하지 않더라도 이 단계는 중요합니다. 사용자가 앱에서 로그아웃할 때 모든 도메인의 인증 상태가 사용하는 Play 서비스 API도 재설정됩니다.

다음 단계

Google 사용자 인증 정보를 가져오도록 원탭 클라이언트를 구성한 경우 앱이 사용자의 개인 식별 정보를 나타내는 Google ID 토큰을 Google 계정. 알아보기 백엔드에서 토큰을 사용하는 방법

Google 로그인을 지원하는 경우 원탭 클라이언트를 사용하여 원활한 계정 생성 흐름을 앱에 도입하세요.