การลงชื่อเข้าใช้บัญชีที่ลิงก์สำหรับ Android

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

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

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

วิธีการทำงาน

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

ตั้งค่า

ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์

รับบริการ Google Play เวอร์ชันล่าสุดในโฮสต์การพัฒนาโดยทำดังนี้

  1. เปิดเครื่องมือจัดการ Android SDK
  1. ในส่วนเครื่องมือ SDK ให้ค้นหาบริการ Google Play

  2. หากสถานะสำหรับแพ็กเกจเหล่านี้คือ "ไม่ได้ติดตั้ง" ให้เลือกทั้ง 2 แพ็กเกจแล้วคลิก ติดตั้งแพ็กเกจ

กำหนดค่าแอป

  1. ในไฟล์ build.gradle ระดับโปรเจ็กต์ ให้ใส่ที่เก็บ Maven ของ Google ทั้งในส่วน buildscript และ allprojects

    buildscript {
        repositories {
            google()
        }
    }
    
    allprojects {
        repositories {
            google()
        }
    }
    
  2. เพิ่มทรัพยากร Dependency สำหรับ API "ลิงก์กับ Google" ลงในไฟล์ Gradle ระดับแอปของโมดูล ซึ่งโดยปกติจะเป็น app/build.gradle

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

แก้ไขแอป Android เพื่อรองรับการลงชื่อเข้าใช้บัญชีที่ลิงก์

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

ตัวอย่างโค้ดต่อไปนี้แสดงรายละเอียดขั้นตอนในการดึงข้อมูล ยืนยันโทเค็นรหัส และหลังจากนั้น ให้ผู้ใช้ลงชื่อเข้าใช้

  1. สร้างกิจกรรมเพื่อรับผลลัพธ์ของ Intent การลงชื่อเข้าใช้

    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. สร้างคำขอลงชื่อเข้าใช้

    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. เปิด Intent ที่รอการลงชื่อเข้าใช้

    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);
    });
    

ยืนยันความสมบูรณ์ของโทเค็นรหัส

ในการยืนยันว่าโทเค็นถูกต้อง ให้ตรวจสอบสิ่งต่อไปนี้ เป็นไปตามเกณฑ์ต่อไปนี้

  • Google ลงชื่อโทเค็นรหัสอย่างถูกต้อง ใช้คีย์สาธารณะของ Google (มีให้บริการใน JWK หรือ PEM) เพื่อยืนยันลายเซ็นของโทเค็น คีย์เหล่านี้จะมีการหมุนเวียนเป็นประจำ ตรวจสอบ ส่วนหัว Cache-Control ในการตอบกลับเพื่อกำหนดเวลาที่ คุณควรดึงข้อมูลอีกครั้ง
  • ค่า aud ในโทเค็นรหัสเท่ากับหนึ่งในแอปของคุณ Client-ID การตรวจสอบนี้จำเป็นต่อการป้องกันโทเค็นรหัสที่ออกให้กับเครื่องมือที่เป็นอันตราย ที่ใช้เข้าถึงข้อมูลเกี่ยวกับผู้ใช้รายเดียวกันในเซิร์ฟเวอร์แบ็กเอนด์ของแอป
  • ค่าของ iss ในโทเค็นรหัสเท่ากับ accounts.google.comหรือhttps://accounts.google.com
  • โทเค็นรหัสยังไม่เลยเวลาหมดอายุ (exp)
  • หากต้องการตรวจสอบว่าโทเค็นรหัสแสดงถึง Google Workspace หรือ Cloud บัญชีขององค์กร คุณสามารถตรวจสอบการอ้างสิทธิ์ hd ซึ่งระบุการอ้างสิทธิ์ที่โฮสต์ไว้ โดเมนของผู้ใช้ ต้องใช้เมื่อจำกัดการเข้าถึงทรัพยากรไว้สำหรับสมาชิกของ บางโดเมน การที่ไม่มีการอ้างสิทธิ์นี้แสดงว่าบัญชีไม่ได้เป็นของ โดเมนที่ Google โฮสต์

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

กรณีที่ Google เชื่อถือได้

  • email มีส่วนต่อท้าย @gmail.com นี่คือบัญชี Gmail
  • email_verified เป็นจริงและตั้งค่า hd แล้ว นี่คือบัญชี G Suite

ผู้ใช้อาจลงทะเบียนบัญชี Google โดยไม่ใช้ Gmail หรือ G Suite ได้ วันและเวลา email ไม่มีคำต่อท้าย @gmail.com และ hd ไม่มี Google ไม่มี แนะนำให้ใช้รหัสผ่านหรือวิธีการอื่นๆ ในการพิสูจน์ยืนยัน ผู้ใช้รายนั้น email_verified ก็อาจเป็นจริงได้ เนื่องจาก Google ได้ยืนยัน ผู้ใช้เมื่อมีการสร้างบัญชี Google แต่การเป็นเจ้าของของบุคคลที่สาม บัญชีอีเมลของคุณอาจมีการเปลี่ยนแปลง

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

ใช้ไลบรารีของไคลเอ็นต์ Google API

การใช้ ไลบรารีไคลเอ็นต์ Java Google API เป็นวิธีที่แนะนำในการตรวจสอบโทเค็น Google ID ในสภาพแวดล้อมการใช้งานจริง

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.");
  }

เมธอด GoogleIdTokenVerifier.verify() จะยืนยันลายเซ็น JWT การอ้างสิทธิ์ aud, การอ้างสิทธิ์ iss และการอ้างสิทธิ์เหล่านั้นexp

หากต้องการตรวจสอบว่าโทเค็นรหัสแสดงถึง Google Workspace หรือ Cloud บัญชีขององค์กร คุณสามารถยืนยันการอ้างสิทธิ์ hd โดยการตรวจสอบชื่อโดเมน แสดงผลโดยเมธอด Payload.getHostedDomain()

การเรียกใช้ปลายทางTokeninfo

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

หากต้องการตรวจสอบโทเค็นรหัสโดยใช้ปลายทาง tokeninfo ให้สร้าง HTTPS คำขอ POST หรือ GET ไปยังปลายทาง แล้วส่งโทเค็นรหัสใน พารามิเตอร์ id_token เช่น หากต้องการตรวจสอบโทเค็น "XYZ123" ให้ส่งคำขอ GET ต่อไปนี้

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

หากโทเค็นมีการรับรองอย่างถูกต้อง และ iss และ exp จะมีค่าที่คาดไว้ คุณจะได้รับการตอบสนอง HTTP 200 โดยที่ส่วนเนื้อหา มีการอ้างสิทธิ์โทเค็นรหัสในรูปแบบ JSON ตัวอย่างคำตอบมีดังนี้

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

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