ให้ผู้ใช้ลงชื่อเข้าใช้ด้วยข้อมูลเข้าสู่ระบบที่บันทึกไว้

ใช้ไคลเอ็นต์การลงชื่อเข้าใช้ด้วย One Tap เพื่อขอสิทธิ์จากผู้ใช้เพื่อเรียกข้อมูล หนึ่งในข้อมูลเข้าสู่ระบบที่ผู้ใช้เคยใช้เพื่อลงชื่อเข้าใช้แอปของคุณ เหล่านี้ ข้อมูลเข้าสู่ระบบอาจเป็นบัญชี Google หรือทั้งชื่อผู้ใช้-รหัสผ่านก็ได้ ที่บันทึกไว้กับ Google โดยใช้ Chrome, การป้อนข้อความอัตโนมัติของ Android หรือ Smart Lock สำหรับ รหัสผ่าน

UI การลงชื่อเข้าใช้ด้วยการแตะเพียงครั้งเดียว

เมื่อดึงข้อมูลเข้าสู่ระบบเรียบร้อยแล้ว คุณจะสามารถใช้ได้อย่างราบรื่น ให้ผู้ใช้ลงชื่อเข้าใช้แอป

หากผู้ใช้ไม่ได้บันทึกข้อมูลเข้าสู่ระบบไว้ ระบบจะไม่แสดง UI และคุณสามารถ มอบประสบการณ์การออกจากระบบตามปกติ

ฉันควรใช้การลงชื่อเข้าใช้ด้วย One Tap ที่ใด

หากกำหนดให้ผู้ใช้ต้องลงชื่อเข้าใช้แอป ให้แสดง UI ของ One Tap ในการลงชื่อเข้าใช้ บนหน้าจอ การดำเนินการนี้อาจเป็นประโยชน์แม้ว่าคุณจะมี "ลงชื่อเข้าใช้ด้วย Google" อยู่แล้ว ปุ่ม: เนื่องจากสามารถกำหนดค่า UI ด้วยการแตะเพียงครั้งเดียวให้แสดงเฉพาะข้อมูลเข้าสู่ระบบ ที่ผู้ใช้เคยลงชื่อเข้าใช้ก่อนหน้านี้ การแจ้งเตือนผู้ใช้ที่ ลงชื่อเข้าใช้ในครั้งล่าสุด และป้องกันไม่ให้ผู้ใช้ การสร้างบัญชีใหม่ด้วยแอปของคุณ

หากแอปไม่จำเป็นต้องลงชื่อเข้าใช้ ให้พิจารณาใช้การลงชื่อเข้าใช้ด้วย One Tap หน้าจอที่มีประสบการณ์การใช้งานที่ดีขึ้นโดยการลงชื่อเข้าใช้ เช่น หากผู้ใช้สามารถ เรียกดูเนื้อหาด้วยแอปขณะออกจากระบบ แต่จะโพสต์ความคิดเห็นหรือเพิ่มได้เท่านั้น สินค้าไปยังรถเข็นช็อปปิ้งหลังจากลงชื่อเข้าใช้ นั่นเป็นบริบทที่เหมาะสมสำหรับ การลงชื่อเข้าใช้ด้วย One Tap

แอปเสริมในการลงชื่อเข้าใช้ควรใช้การลงชื่อเข้าใช้ด้วย One Tap ในหน้าจอลงชื่อเข้าใช้ด้วย ด้วยเหตุผลที่ระบุไว้ข้างต้น

ก่อนเริ่มต้น

1. กำหนดค่าไคลเอ็นต์การลงชื่อเข้าใช้ด้วย One Tap

คุณสามารถกำหนดค่าไคลเอ็นต์การลงชื่อเข้าใช้ด้วย One Tap เพื่อให้ผู้ใช้ลงชื่อเข้าใช้ด้วย รหัสผ่าน บัญชี Google ที่บันทึกไว้ หรือวิธีใดวิธีหนึ่ง (ขอแนะนำให้รองรับทั้ง 2 รูปแบบเพื่อ เปิดใช้การสร้างบัญชีด้วยการแตะเพียงครั้งเดียวสำหรับผู้ใช้ใหม่ และการลงชื่อเข้าใช้โดยอัตโนมัติหรือการแตะเพียงครั้งเดียว สำหรับผู้ใช้ที่กลับมาให้มากที่สุด)

หากแอปใช้การลงชื่อเข้าใช้ด้วยรหัสผ่าน ให้ใช้ setPasswordRequestOptions() เพื่อ เปิดใช้งานคำขอข้อมูลเข้าสู่ระบบรหัสผ่าน

หากแอปใช้ Google Sign-In ให้ใช้ setGoogleIdTokenRequestOptions() เพื่อ เปิดใช้และกำหนดค่าคำขอโทเค็นรหัส Google ดังนี้

  • ตั้งค่ารหัสไคลเอ็นต์ของเซิร์ฟเวอร์เป็นรหัสที่คุณสร้างใน Google APIs โปรดทราบว่านี่เป็นรหัสไคลเอ็นต์ของเซิร์ฟเวอร์ของคุณ ไม่ใช่ รหัสไคลเอ็นต์ของ Android

  • กำหนดค่าไคลเอ็นต์เพื่อกรองตามบัญชีที่ได้รับอนุญาต เมื่อคุณเปิดใช้ตัวเลือกนี้ ไคลเอ็นต์ One Tap บอกให้ผู้ใช้ลงชื่อเข้าใช้แอปของคุณด้วย บัญชี Google ที่เคยใช้แล้วในอดีต การทำเช่นนี้จะช่วยให้ผู้ใช้สามารถลงชื่อเข้าใช้ สำเร็จ เมื่อไม่แน่ใจว่าตนมีบัญชีแล้วหรือไม่ หรือ บัญชี Google ที่ผู้ใช้ใช้ และป้องกันไม่ให้ผู้ใช้สร้างบัญชีใหม่โดยไม่ตั้งใจ บัญชีกับแอปของคุณ

  • ถ้าคุณต้องการให้ผู้ใช้ลงชื่อเข้าใช้โดยอัตโนมัติเมื่อเป็นไปได้ ให้เปิดใช้งานฟีเจอร์นี้ ด้วย setAutoSelectEnabled() การลงชื่อเข้าใช้โดยอัตโนมัติจะทำได้เมื่อ ตรงตามเกณฑ์ต่อไปนี้

    • ผู้ใช้ได้บันทึกข้อมูลเข้าสู่ระบบสำหรับแอปของคุณไว้เพียง 1 รายการ นั่นคือ บันทึก 1 บัญชี รหัสผ่านหรือบัญชี Google ที่บันทึกไว้หนึ่งบัญชี
    • ผู้ใช้ไม่ได้ปิดใช้การลงชื่อเข้าใช้โดยอัตโนมัติในบัญชี การตั้งค่าบัญชี Google
  • แม้จะไม่บังคับ แต่เราขอแนะนำให้คุณพิจารณาใช้ Nonce เพื่อ เพิ่มความปลอดภัยในการลงชื่อเข้าใช้และหลีกเลี่ยงการโจมตีซ้ำ ใช้ setNonce เพื่อใส่ค่า Nonce ในคำขอแต่ละรายการ ดูของ SafetyNet ได้ค่า Nonce สำหรับคำแนะนำและรายละเอียดเพิ่มเติมเกี่ยวกับการสร้าง Nonce

Java

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 การลงชื่อเข้าใช้ด้วย One Tap

นอกจากนี้ คุณควรติดตามว่าผู้ใช้ได้ปฏิเสธการใช้แล้วหรือไม่ ลงชื่อเข้าใช้ด้วย One Tap โดยการปิดข้อความแจ้งหรือแตะด้านนอก วิธีนี้ เรียบง่ายเหมือนพร็อพเพอร์ตี้บูลีนของกิจกรรมของคุณ (ดูหยุดแสดง UI แบบแตะครั้งเดียวด้านล่าง)

3. แสดง UI การลงชื่อเข้าใช้ด้วย One Tap

หากผู้ใช้ไม่ได้ลงชื่อเข้าใช้และยังไม่ได้ปฏิเสธที่จะใช้การลงชื่อเข้าใช้ด้วย One Tap เรียกเมธอด beginSignIn() ของออบเจ็กต์ไคลเอ็นต์และแนบ Listener เข้ากับฟังก์ชัน Task รายการที่ส่งคืน โดยปกติแล้ว แอปจะดำเนินการนี้ในเมธอด onCreate() ของกิจกรรม หรือหลังจากที่เปลี่ยนหน้าจอเมื่อใช้สถาปัตยกรรม "กิจกรรมเดียว"

ไคลเอ็นต์ One Tap จะโทรหา Listener ที่ดำเนินการสำเร็จหากผู้ใช้ได้บันทึกแล้ว สำหรับแอปของคุณ ใน Listener ที่สำเร็จ ให้รับ Intent ที่รอดำเนินการจาก ผลลัพธ์ Task และส่งไปยัง startIntentSenderForResult() เพื่อเริ่มต้น UI การลงชื่อเข้าใช้ด้วย One Tap

หากผู้ใช้ไม่มีข้อมูลเข้าสู่ระบบใดๆ ที่บันทึกไว้ ไคลเอ็นต์ One Tap จะเรียกเมธอด Listener ล้มเหลว ในกรณีนี้ คุณไม่ต้องดำเนินการใดๆ เพียงแค่ดำเนินการต่อ นำเสนอประสบการณ์การออกจากระบบของแอป อย่างไรก็ตาม หากคุณรองรับ One Tap คุณสามารถเริ่มดำเนินการดังกล่าวได้ที่นี่เพื่อให้สร้างบัญชีได้อย่างราบรื่น ประสบการณ์การใช้งาน โปรดดูหัวข้อสร้างบัญชีใหม่ด้วยการแตะเพียงครั้งเดียว

Java

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. จัดการคำตอบของผู้ใช้

คำตอบของผู้ใช้ต่อข้อความแจ้งให้ลงชื่อเข้าใช้ด้วย One Tap จะได้รับการรายงานไปยังแอปของคุณ โดยใช้เมธอด onActivityResult() ของกิจกรรม หากผู้ใช้เลือกลงชื่อเข้าใช้ ผลการค้นหาจะเป็นข้อมูลเข้าสู่ระบบที่บันทึกไว้ หากผู้ใช้ปฏิเสธการลงชื่อเข้าใช้ ด้วยการปิด One Tap UI หรือแตะด้านนอก ผลลัพธ์จะแสดงพร้อม รหัส RESULT_CANCELED แอปของคุณต้องรับมือกับทั้ง 2 ความเป็นไปได้

ลงชื่อเข้าใช้ด้วยข้อมูลเข้าสู่ระบบที่ดึงมา

หากผู้ใช้เลือกแชร์ข้อมูลเข้าสู่ระบบกับแอปของคุณ คุณจะเรียกข้อมูลได้โดย กำลังส่งข้อมูล Intent จาก onActivityResult() ไปยัง getSignInCredentialFromIntent() วิธี ข้อมูลเข้าสู่ระบบจะมีค่าที่ไม่เป็น Null พร็อพเพอร์ตี้ googleIdToken หากผู้ใช้แชร์ข้อมูลเข้าสู่ระบบของบัญชี Google กับ แอปของคุณ หรือพร็อพเพอร์ตี้ password ที่ไม่เป็นค่าว่าง หากผู้ใช้แชร์รหัสผ่านที่บันทึกไว้

ใช้ข้อมูลเข้าสู่ระบบเพื่อตรวจสอบสิทธิ์กับแบ็กเอนด์ของแอป

  • หากมีการเรียกชื่อผู้ใช้และรหัสผ่าน ให้ใช้คู่เดียวกันในการลงชื่อเข้าใช้ วิธีที่คุณควรทำหากผู้ใช้ระบุเอง
  • หากมีการดึงข้อมูลเข้าสู่ระบบของบัญชี Google ให้ใช้โทเค็นรหัสในการตรวจสอบสิทธิ์ กับแบ็กเอนด์ของคุณ หากคุณเลือกใช้ Nonce เพื่อหลีกเลี่ยงการเล่นซ้ำ จะตรวจสอบค่าการตอบสนองในเซิร์ฟเวอร์แบ็กเอนด์ของคุณ โปรดดู ตรวจสอบสิทธิ์กับแบ็กเอนด์โดยใช้โทเค็นรหัส

Java

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() จะแสดง ApiException ที่มีรหัสสถานะ CommonStatusCodes.CANCELED เมื่อเกิดกรณีนี้ขึ้น คุณควรปิดใช้ UI การลงชื่อเข้าใช้ด้วย One Tap ชั่วคราวเพื่อ อย่าทำให้ผู้ใช้รำคาญด้วยข้อความแจ้งซ้ำๆ ตัวอย่างความสำเร็จต่อไปนี้ โดยการตั้งค่าพร็อพเพอร์ตี้ใน "กิจกรรม" ซึ่งจะใช้เพื่อกำหนดว่า เพื่อเสนอการลงชื่อเข้าใช้ด้วย One Tap ให้แก่ผู้ใช้ อย่างไรก็ตาม คุณสามารถบันทึกค่าลงใน SharedPreferencesหรือใช้วิธีอื่น

คุณควรใช้การจำกัดอัตราคำขอลงชื่อเข้าใช้ด้วย One Tap ด้วยตัวเอง หากไม่ยกเลิก และผู้ใช้ยกเลิกข้อความแจ้งหลายรายการติดต่อกัน ไคลเอ็นต์ One Tap จะไม่แจ้งให้ผู้ใช้ทราบเป็นเวลา 24 ชั่วโมงต่อจากนี้

Java

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() ของไคลเอ็นต์ One Tap การเรียกใช้ signOut() จะปิดการลงชื่อเข้าใช้โดยอัตโนมัติจนกว่าผู้ใช้จะลงชื่อเข้าใช้อีกครั้ง

แม้ว่าคุณจะไม่ได้ใช้การลงชื่อเข้าใช้โดยอัตโนมัติ แต่ขั้นตอนนี้ก็มีความสำคัญเนื่องจาก ตรวจสอบว่าเมื่อผู้ใช้ออกจากระบบแอป สถานะการตรวจสอบสิทธิ์ นอกจากนี้ API ของบริการ Google Play ที่คุณใช้จะถูกรีเซ็ตด้วย

ขั้นตอนถัดไป

หากคุณกำหนดค่าไคลเอ็นต์ One Tap ให้ดึงข้อมูลเข้าสู่ระบบ Google แอปของคุณ จะสามารถรับโทเค็น Google ID ที่แสดงถึงผู้ใช้ บัญชี Google ดูข้อมูล คุณจะใช้โทเค็นเหล่านี้ในแบ็กเอนด์ได้อย่างไร

หากคุณรองรับ Google Sign-In คุณสามารถใช้ไคลเอ็นต์ One Tap เพื่อเพิ่ม ขั้นตอนการสร้างบัญชีที่ราบรื่นไปยังแอปของคุณ