ตรวจสอบสิทธิ์ผู้ใช้ด้วยฟีเจอร์ลงชื่อเข้าใช้ด้วย Google

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

เอกสารนี้จะแนะนำวิธีใช้ฟีเจอร์ลงชื่อเข้าใช้ด้วย Google ในแอป Android, วิธีตั้งค่า UI ปุ่มลงชื่อเข้าใช้ด้วย Google และวิธีกำหนดค่าประสบการณ์การลงชื่อสมัครใช้และลงชื่อเข้าใช้แบบ One Tap ที่เพิ่มประสิทธิภาพให้แอป การลงชื่อเข้าใช้ด้วย Google รองรับการลงชื่อเข้าใช้อัตโนมัติ และความสามารถในการทำงานข้ามแพลตฟอร์มใน Android, iOS และเว็บช่วยให้คุณมอบสิทธิ์เข้าถึงการลงชื่อเข้าใช้สำหรับแอปในอุปกรณ์ทุกเครื่องได้ เพื่อการเปลี่ยนอุปกรณ์ที่ราบรื่น

หากต้องการตั้งค่าฟีเจอร์ลงชื่อเข้าใช้ด้วย Google ให้ทำตามขั้นตอนหลัก 2 ขั้นตอนต่อไปนี้

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

Bottom Sheet ของเครื่องมือจัดการข้อมูลเข้าสู่ระบบ
รูปที่ 1 ชีตด้านล่างของเครื่องมือจัดการข้อมูลเข้าสู่ระบบ UI การเลือกข้อมูลเข้าสู่ระบบ

เพิ่มปุ่มลงชื่อเข้าใช้ด้วย Google ลงใน UI ของแอป ปุ่ม "ลงชื่อเข้าใช้ด้วย Google" มอบวิธีที่มีประสิทธิภาพยิ่งขึ้นสำหรับผู้ใช้ในการใช้บัญชี Google ที่มีอยู่เพื่อลงชื่อสมัครใช้หรือลงชื่อเข้าใช้แอป Android ผู้ใช้จะคลิกปุ่มลงชื่อเข้าใช้ด้วย Google หากปิด UI ของชีตด้านล่าง หรือหากต้องการใช้บัญชี Google เพื่อลงชื่อสมัครใช้และลงชื่อเข้าใช้อย่างชัดเจน สําหรับนักพัฒนาแอป การเปลี่ยนแปลงนี้จะช่วยให้ผู้ใช้เริ่มต้นใช้งานได้ง่ายขึ้นและลดปัญหาที่เกิดขึ้นระหว่างการลงชื่อสมัครใช้

ภาพเคลื่อนไหวแสดงขั้นตอนการลงชื่อเข้าใช้ด้วย Google
รูปที่ 2 UI ปุ่มลงชื่อเข้าใช้ด้วย Google ของ Credential Manager

เอกสารนี้อธิบายวิธีผสานรวมปุ่มลงชื่อเข้าใช้ด้วย Google และกล่องโต้ตอบในชีตด้านล่างกับ Credential Manager API โดยใช้ไลบรารีตัวช่วย GoogleID

ตั้งค่าโปรเจ็กต์คอนโซล Google API

  1. เปิดโปรเจ็กต์ในคอนโซล API หรือสร้างโปรเจ็กต์หากยังไม่มี
  2. ในหน้าหน้าจอคำยินยอม OAuth ให้ตรวจสอบว่าข้อมูลทั้งหมดครบถ้วนและถูกต้อง
    1. ตรวจสอบว่าแอปมีชื่อแอป โลโก้แอป และหน้าแรกของแอปที่ถูกต้อง ค่าเหล่านี้จะแสดงต่อผู้ใช้ในหน้าจอขอความยินยอมของฟีเจอร์ลงชื่อเข้าใช้ด้วย Google เมื่อลงชื่อสมัครใช้และในหน้าจอแอปและบริการของบุคคลที่สาม
    2. ตรวจสอบว่าคุณได้ระบุ URL ของนโยบายความเป็นส่วนตัวและข้อกำหนดในการให้บริการของแอปแล้ว
  3. ในหน้าข้อมูลเข้าสู่ระบบ ให้สร้างรหัสไคลเอ็นต์ Android สำหรับแอปหากยังไม่มี คุณจะต้องระบุชื่อแพ็กเกจของแอปและลายเซ็น SHA-1
    1. ไปที่หน้าข้อมูลเข้าสู่ระบบ
    2. คลิกสร้างข้อมูลเข้าสู่ระบบ > รหัสไคลเอ็นต์ OAuth
    3. เลือกประเภทแอปพลิเคชัน Android
  4. ในหน้าข้อมูลเข้าสู่ระบบ ให้สร้างรหัสไคลเอ็นต์ "เว็บแอปพลิเคชัน" ใหม่หากยังไม่ได้สร้าง คุณไม่ต้องสนใจช่อง "ต้นทาง JavaScript ที่ได้รับอนุญาต" และ "URI การเปลี่ยนเส้นทางที่ได้รับอนุญาต" ในตอนนี้ รหัสไคลเอ็นต์นี้จะใช้เพื่อระบุเซิร์ฟเวอร์แบ็กเอนด์เมื่อสื่อสารกับบริการการตรวจสอบสิทธิ์ของ Google
    1. ไปที่หน้าข้อมูลเข้าสู่ระบบ
    2. คลิกสร้างข้อมูลเข้าสู่ระบบ > รหัสไคลเอ็นต์ OAuth
    3. เลือกประเภทเว็บแอปพลิเคชัน

ประกาศทรัพยากร Dependency

ในไฟล์ create.gradle ของโมดูล ให้ประกาศทรัพยากร Dependency โดยใช้เครื่องมือจัดการข้อมูลเข้าสู่ระบบเวอร์ชันล่าสุด ดังนี้

dependencies {
  // ... other dependencies

  implementation "androidx.credentials:credentials:<latest version>"
  implementation "androidx.credentials:credentials-play-services-auth:<latest version>"
  implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"
}

สร้างอินสแตนซ์คำขอลงชื่อเข้าใช้ด้วย Google

ในการเริ่มต้นใช้งาน ให้สร้างอินสแตนซ์คำขอลงชื่อเข้าใช้ Google ใช้ GetGoogleIdOption เพื่อเรียกโทเค็นรหัส Google ของผู้ใช้

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

ก่อนอื่น ให้ตรวจสอบว่าผู้ใช้มีบัญชีที่เคยใช้ลงชื่อเข้าใช้แอปหรือไม่โดยเรียก API โดยตั้งค่าพารามิเตอร์ setFilterByAuthorizedAccounts เป็น true ผู้ใช้สามารถเลือกลงชื่อเข้าใช้ด้วยบัญชีใดก็ได้ที่มี

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

เปิดใช้การลงชื่อเข้าใช้โดยอัตโนมัติสำหรับผู้ใช้ที่กลับมา (แนะนำ)

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

หากต้องการเปิดใช้การลงชื่อเข้าใช้อัตโนมัติ ให้ใช้ setAutoSelectEnabled(true) การลงชื่อเข้าใช้โดยอัตโนมัติจะทําได้ก็ต่อเมื่อมีคุณสมบัติตรงตามเกณฑ์ต่อไปนี้เท่านั้น

  • มีข้อมูลเข้าสู่ระบบรายการเดียวที่ตรงกับคำขอ ซึ่งอาจเป็นบัญชี Google หรือรหัสผ่าน และข้อมูลเข้าสู่ระบบนี้ตรงกับบัญชีเริ่มต้นในอุปกรณ์ Android
  • ผู้ใช้ไม่ได้ออกจากระบบอย่างชัดเจน
  • ผู้ใช้ไม่ได้ปิดใช้การลงชื่อเข้าใช้โดยอัตโนมัติในการตั้งค่าบัญชี Google
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

อย่าลืมจัดการการออกจากระบบให้ถูกต้องเมื่อใช้การลงชื่อเข้าใช้โดยอัตโนมัติ เพื่อให้ผู้ใช้เลือกบัญชีที่เหมาะสมได้เสมอหลังจากออกจากระบบของแอปอย่างชัดเจน

ตั้งค่า Nonce เพื่อปรับปรุงความปลอดภัย

หากต้องการเพิ่มความปลอดภัยในการลงชื่อเข้าใช้และหลีกเลี่ยงการโจมตีด้วยการเล่นซ้ำ ให้เพิ่ม setNonce เพื่อใส่ Nonce ในแต่ละคำขอ ดูข้อมูลเพิ่มเติมเกี่ยวกับการสร้าง Nonce

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

สร้างขั้นตอนการลงชื่อเข้าใช้ด้วย Google

ขั้นตอนในการตั้งค่าขั้นตอนการลงชื่อเข้าใช้ด้วย Google มีดังนี้

  1. สร้าง GetCredentialRequest ขึ้นมา แล้วเพิ่ม googleIdOption ที่สร้างขึ้นก่อนหน้านี้โดยใช้ addCredentialOption() เพื่อเรียกข้อมูลเข้าสู่ระบบ
  2. ส่งต่อคำขอนี้ไปยังการเรียกใช้ getCredential() (Kotlin) หรือ getCredentialAsync() (Java) เพื่อเรียกข้อมูลเข้าสู่ระบบของผู้ใช้
  3. เมื่อ API เสร็จสมบูรณ์แล้ว ให้แยก CustomCredential ที่เก็บผลลัพธ์สำหรับข้อมูล GoogleIdTokenCredential
  4. ประเภทของ CustomCredential ควรเท่ากับค่าของ GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL แปลงออบเจ็กต์เป็น GoogleIdTokenCredential โดยใช้เมธอด GoogleIdTokenCredential.createFrom
  5. หากแปลงสำเร็จ ให้ดึงข้อมูลรหัส GoogleIdTokenCredential,ตรวจสอบ และตรวจสอบสิทธิ์ข้อมูลเข้าสู่ระบบในเซิร์ฟเวอร์

  6. หาก Conversion ล้มเหลวด้วย GoogleIdTokenParsingException คุณอาจต้องอัปเดตเวอร์ชันคลังฟีเจอร์ลงชื่อเข้าใช้ด้วย Google

  7. จับประเภทข้อมูลเข้าสู่ระบบที่กำหนดเองที่ไม่รู้จัก

val request: GetCredentialRequest = Builder()
  .addCredentialOption(googleIdOption)
  .build()

coroutineScope.launch {
  try {
    val result = credentialManager.getCredential(
      request = request,
      context = activityContext,
    )
    handleSignIn(result)
  } catch (e: GetCredentialException) {
    handleFailure(e)
  }
}

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {

    // Passkey credential
    is PublicKeyCredential -> {
      // Share responseJson such as a GetCredentialResponse on your server to
      // validate and authenticate
      responseJson = credential.authenticationResponseJson
    }

    // Password credential
    is PasswordCredential -> {
      // Send ID and password to your server to validate and authenticate.
      val username = credential.id
      val password = credential.password
    }

    // GoogleIdToken credential
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract the ID to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
          // You can use the members of googleIdTokenCredential directly for UX
          // purposes, but don't use them to store or control access to user
          // data. For that you first need to validate the token:
          // pass googleIdTokenCredential.getIdToken() to the backend server.
          GoogleIdTokenVerifier verifier = ... // see validation instructions
          GoogleIdToken idToken = verifier.verify(idTokenString);
          // To get a stable account identifier (e.g. for storing user data),
          // use the subject ID:
          idToken.getPayload().getSubject()
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      } else {
        // Catch any unrecognized custom credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

ทริกเกอร์ขั้นตอนปุ่มลงชื่อเข้าใช้ด้วย Google

หากต้องการเรียกใช้การทำงานของปุ่มลงชื่อเข้าใช้ด้วย Google ให้ใช้ GetSignInWithGoogleOption แทน GetGoogleIdOption ดังนี้

val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder()
  .setServerClientId(WEB_CLIENT_ID)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

จัดการ GoogleIdTokenCredential ที่แสดงผลตามที่อธิบายในตัวอย่างโค้ดต่อไปนี้

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract id to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      }
      else -> {
        // Catch any unrecognized credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

เมื่อคุณสร้างอินสแตนซ์คำขอลงชื่อเข้าใช้ของ Google แล้ว ให้เปิดขั้นตอนการตรวจสอบสิทธิ์ในลักษณะเดียวกันดังที่อธิบายในส่วนลงชื่อเข้าใช้ด้วย Google

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

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

หากไม่พบข้อมูลเข้าสู่ระบบที่บันทึกไว้ (ไม่มีบัญชี Google ที่แสดงโดย getGoogleIdOption) ให้แจ้งให้ผู้ใช้ลงชื่อสมัครใช้ ก่อนอื่น ให้ตรวจสอบว่า setFilterByAuthorizedAccounts(true) เพื่อดูว่ามีบัญชีที่เคยใช้อยู่หรือไม่ หากไม่พบ ให้แจ้งให้ผู้ใช้ลงชื่อสมัครใช้ด้วยบัญชี Google โดยใช้ setFilterByAuthorizedAccounts(false)

ตัวอย่าง

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(false)
  .setServerClientId(WEB_CLIENT_ID)
  .build()

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

จัดการการออกจากระบบ

เมื่อผู้ใช้ออกจากระบบแอป ให้เรียกใช้เมธอด API clearCredentialState() เพื่อล้างสถานะข้อมูลเข้าสู่ระบบปัจจุบันของผู้ใช้จากผู้ให้บริการข้อมูลเข้าสู่ระบบทั้งหมด การดําเนินการนี้จะแจ้งให้ผู้ให้บริการข้อมูลเข้าสู่ระบบทุกรายทราบว่าควรล้างเซสชันข้อมูลเข้าสู่ระบบที่จัดเก็บไว้สําหรับแอปที่ระบุ

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