อนุญาตการเข้าถึงข้อมูลผู้ใช้ Google

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

การเรียกการตรวจสอบสิทธิ์และการให้สิทธิ์ควรเป็น 2 ขั้นตอนที่แยกกันและแตกต่างกัน ตามความต้องการของแอป

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

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

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

สำหรับการตรวจสอบสิทธิ์ เราขอแนะนำให้ใช้ Credential Manager API สําหรับการให้สิทธิ์การดําเนินการที่ต้องเข้าถึงข้อมูลผู้ใช้ที่ Google จัดเก็บไว้ เราขอแนะนําให้ใช้ AuthorizationClient

สร้าง โปรเจ็กต์

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

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

ในไฟล์ build.gradle ของโมดูล ให้ประกาศการขึ้นต่อกันโดยใช้ไลบรารีบริการข้อมูลประจำตัวของ Google เวอร์ชันล่าสุด

dependencies {   // ... other dependencies    implementation "com.google.android.gms:play-services-auth:21.4.0" } 

ขอสิทธิ์ที่การดำเนินการของผู้ใช้ต้องใช้

เมื่อใดก็ตามที่ผู้ใช้ดำเนินการที่ต้องใช้ขอบเขตเพิ่มเติม ให้เรียกใช้ AuthorizationClient.authorize() เช่น หากผู้ใช้ดำเนินการ ที่ต้องเข้าถึงพื้นที่เก็บข้อมูลของแอปไดรฟ์ ให้ทำดังนี้

Kotlin

val requestedScopes: List<Scope> = listOf(DriveScopes.DRIVE_FILE) val authorizationRequest = AuthorizationRequest.builder()     .setRequestedScopes(requestedScopes)     .build()  Identity.getAuthorizationClient(activity)     .authorize(authorizationRequestBuilder.build())     .addOnSuccessListener { authorizationResult ->         if (authorizationResult.hasResolution()) {             val pendingIntent = authorizationResult.pendingIntent             // Access needs to be granted by the user             startAuthorizationIntent.launchIntentSenderRequest.Builder(pendingIntent!!.intentSender).build()         } else {             // Access was previously granted, continue with user action             saveToDriveAppFolder(authorizationResult);         }     }     .addOnFailureListener { e -> Log.e(TAG, "Failed to authorize", e) } 

Java

List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_FILE); AuthorizationRequest authorizationRequest = AuthorizationRequest.builder()     .setRequestedScopes(requestedScopes)     .build();  Identity.getAuthorizationClient(activity)     .authorize(authorizationRequest)     .addOnSuccessListener(authorizationResult -> {         if (authorizationResult.hasResolution()) {             // Access needs to be granted by the user             startAuthorizationIntent.launch(                 new IntentSenderRequest.Builder(                     authorizationResult.getPendingIntent().getIntentSender()                 ).build()             );         } else {             // Access was previously granted, continue with user action             saveToDriveAppFolder(authorizationResult);         }     })     .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e)); 

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

Kotlin

private lateinit var startAuthorizationIntent: ActivityResultLauncher<IntentSenderRequest>  override fun onCreateView(     inflater: LayoutInflater,     container: ViewGroup?,     savedInstanceState: Bundle?, ): View? {     // ...     startAuthorizationIntent =         registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->             try {                 // extract the result                 val authorizationResult = Identity.getAuthorizationClient(requireContext())                     .getAuthorizationResultFromIntent(activityResult.data)                 // continue with user action                 saveToDriveAppFolder(authorizationResult);             } catch (ApiException e) {                 // log exception             }         } } 

Java

private ActivityResultLauncher<IntentSenderRequest> startAuthorizationIntent;  @Override public View onCreateView(     @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // ... startAuthorizationIntent =     registerForActivityResult(         new ActivityResultContracts.StartIntentSenderForResult(),         activityResult -> {             try {             // extract the result             AuthorizationResult authorizationResult =                 Identity.getAuthorizationClient(requireActivity())                     .getAuthorizationResultFromIntent(activityResult.getData());             // continue with user action             saveToDriveAppFolder(authorizationResult);             } catch (ApiException e) {             // log exception             }         }); } 

หากเข้าถึง Google API ในฝั่งเซิร์ฟเวอร์ ให้เรียกใช้เมธอด getServerAuthCode() จาก AuthorizationResult เพื่อรับรหัสการให้สิทธิ์ซึ่งคุณจะส่งไปยังแบ็กเอนด์เพื่อแลกเป็นโทเค็นเพื่อการเข้าถึงและโทเค็นเพื่อการรีเฟรช ดูข้อมูลเพิ่มเติมได้ที่รักษาสิทธิ์เข้าถึงข้อมูลของผู้ใช้ต่อไป

เพิกถอนสิทธิ์เข้าถึงข้อมูลหรือทรัพยากรของผู้ใช้

หากต้องการเพิกถอนสิทธิ์เข้าถึงที่ให้ไว้ก่อนหน้านี้ ให้โทรหา AuthorizationClient.revokeAccess() ตัวอย่างเช่น หากผู้ใช้กำลังนำบัญชีออกจากแอปของคุณ และก่อนหน้านี้แอปของคุณได้รับสิทธิ์เข้าถึง DriveScopes.DRIVE_FILE ให้ใช้โค้ดต่อไปนี้เพื่อเพิกถอนสิทธิ์เข้าถึง

Kotlin

val requestedScopes: MutableList<Scope> = mutableListOf(DriveScopes.DRIVE_FILE) RevokeAccessRequest revokeAccessRequest = RevokeAccessRequest.builder()     .setAccount(account)     .setScopes(requestedScopes)     .build()  Identity.getAuthorizationClient(activity)     .revokeAccess(revokeAccessRequest)     .addOnSuccessListener { Log.i(TAG, "Successfully revoked access") }     .addOnFailureListener { e -> Log.e(TAG, "Failed to revoke access", e) } 

Java

List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_FILE); RevokeAccessRequest revokeAccessRequest = RevokeAccessRequest.builder()     .setAccount(account)     .setScopes(requestedScopes)     .build();  Identity.getAuthorizationClient(activity)     .revokeAccess(revokeAccessRequest)     .addOnSuccessListener(unused -> Log.i(TAG, "Successfully revoked access"))     .addOnFailureListener(e -> Log.e(TAG, "Failed to revoke access", e)); 

ล้างแคชโทเค็น

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

Kotlin

Identity.getAuthorizationClient(activity)     .clearToken(ClearTokenRequest.builder().setToken(invalidAccessToken).build())     .addOnSuccessListener { Log.i(TAG, "Successfully removed the token from the cache") }     .addOnFailureListener{ e -> Log.e(TAG, "Failed to clear token", e) } 

Java

Identity.getAuthorizationClient(activity)     .clearToken(ClearTokenRequest.builder().setToken(invalidAccessToken).build())     .addOnSuccessListener(unused -> Log.i(TAG, "Successfully removed the token from the cache"))     .addOnFailureListener(e -> Log.e(TAG, "Failed to clear the token cache", e)); 

รับข้อมูลผู้ใช้ระหว่างการให้สิทธิ์

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

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

  • ในคำขอการให้สิทธิ์ นอกเหนือจากขอบเขตที่คุณต้องการ (เช่น Drive scope) ให้ขอขอบเขต userinfo, profile และ openid หลังจากได้รับโทเค็นเพื่อการเข้าถึงแล้ว ให้รับข้อมูลผู้ใช้โดยส่งGET คำขอ HTTP ไปยังปลายทาง OAuth userinfo (https://www.googleapis.com/oauth2/v3/userinfo) โดยใช้ไลบรารี HTTP ที่ต้องการ และใส่โทเค็นเพื่อการเข้าถึงที่คุณได้รับในส่วนหัว ซึ่งเทียบเท่ากับคำสั่ง curl ต่อไปนี้

    curl -X GET \ "https://www.googleapis.com/oauth2/v1/userinfo?alt=json" \ -H "Authorization: Bearer $TOKEN" 

    การตอบกลับคือ UserInfo ซึ่งจำกัดไว้เฉพาะขอบเขตที่ ขอไว้ และจัดรูปแบบเป็น JSON

การให้สิทธิ์จากบัญชีที่ไม่ใช่บัญชีเริ่มต้น

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

คงสิทธิ์เข้าถึงข้อมูลของผู้ใช้ต่อไป

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

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

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

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

Kotlin

// Ask for offline access during the first authorization request val authorizationRequest = AuthorizationRequest.builder()     .setRequestedScopes(requestedScopes)     .requestOfflineAccess(serverClientId)     .build()  Identity.getAuthorizationClient(activity)     .authorize(authorizationRequest)     .addOnSuccessListener { authorizationResult ->         startAuthorizationIntent.launchIntentSenderRequest.Builder(             pendingIntent!!.intentSender         ).build()     }     .addOnFailureListener { e -> Log.e(TAG, "Failed to authorize", e) } 

Java

// Ask for offline access during the first authorization request AuthorizationRequest authorizationRequest = AuthorizationRequest.builder()     .setRequestedScopes(requestedScopes)     .requestOfflineAccess(serverClientId)     .build();  Identity.getAuthorizationClient(getContext())     .authorize(authorizationRequest)     .addOnSuccessListener(authorizationResult -> {         startAuthorizationIntent.launch(             new IntentSenderRequest.Builder(                 authorizationResult.getPendingIntent().getIntentSender()             ).build()         );     })     .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize")); 

ข้อมูลโค้ดต่อไปนี้ถือว่าการให้สิทธิ์เริ่มต้นจาก Fragment

Kotlin

private lateinit var startAuthorizationIntent: ActivityResultLauncher<IntentSenderRequest>  override fun onCreateView(     inflater: LayoutInflater,     container: ViewGroup?,     savedInstanceState: Bundle?, ): View? {     // ...     startAuthorizationIntent =         registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->             try {                 val authorizationResult = Identity.getAuthorizationClient(requireContext())                     .getAuthorizationResultFromIntent(activityResult.data)                 // short-lived access token                 accessToken = authorizationResult.accessToken                 // store the authorization code used for getting a refresh token safely to your app's backend server                 val authCode: String = authorizationResult.serverAuthCode                 storeAuthCodeSafely(authCode)             } catch (e: ApiException) {                 // log exception             }         } } 

Java

private ActivityResultLauncher<IntentSenderRequest> startAuthorizationIntent;  @Override public View onCreateView(     @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {     // ...     startAuthorizationIntent =         registerForActivityResult(             new ActivityResultContracts.StartIntentSenderForResult(),             activityResult -> {                 try {                     AuthorizationResult authorizationResult =                         Identity.getAuthorizationClient(requireActivity())                             .getAuthorizationResultFromIntent(activityResult.getData());                     // short-lived access token                     accessToken = authorizationResult.getAccessToken();                     // store the authorization code used for getting a refresh token safely to your app's backend server                     String authCode = authorizationResult.getServerAuthCode()                     storeAuthCodeSafely(authCode);                 } catch (ApiException e) {                     // log exception                 }             }); }