ย้ายข้อมูลไปยังบริการ Google Identity

ภาพรวม

Google มีไลบรารี JavaScript หลายรายการเพื่อรับโทเค็นเพื่อการเข้าถึงต่อผู้ใช้เพื่อเรียกใช้ Google API ดังนี้

คู่มือนี้มีวิธีการย้ายข้อมูลจากไลบรารีเหล่านี้ไปยังไลบรารี Google Identity Services

การทำตามคำแนะนำนี้จะช่วยให้คุณทำสิ่งต่อไปนี้ได้

  • แทนที่ Platform Library ที่เลิกใช้งานแล้วด้วย Identity Services Library และ
  • หากใช้ไลบรารีของไคลเอ็นต์ API ให้นำโมดูล gapi.auth2 ที่เลิกใช้แล้ว เมธอดและออบเจ็กต์ของโมดูลออก แล้วแทนที่ด้วยรายการที่เทียบเท่ากับ Identity Services

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

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

ระบุขั้นตอนการให้สิทธิ์

ขั้นตอนการให้สิทธิ์ผู้ใช้มี 2 แบบ ได้แก่ แบบโดยนัยและแบบรหัสการให้สิทธิ์

ตรวจสอบเว็บแอปเพื่อระบุประเภทโฟลว์การให้สิทธิ์ที่ใช้

ข้อบ่งชี้ว่าเว็บแอปของคุณใช้โฟลว์โดยนัย

ข้อบ่งชี้ว่าเว็บแอปของคุณใช้ขั้นตอนรหัสการให้สิทธิ์

ในบางกรณี ฐานโค้ดอาจรองรับทั้ง 2 โฟลว์

เลือกขั้นตอนการให้สิทธิ์

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

โปรดอ่านการเลือกโฟลว์การให้สิทธิ์เพื่อทำความเข้าใจความแตกต่างที่สำคัญ และข้อดีข้อเสียระหว่างโฟลว์ทั้ง 2

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

เลือกโฟลว์การให้สิทธิ์โดยใช้ตัวเลือก

ขั้นตอนการให้สิทธิ์โดยนัย

รับโทเค็นเพื่อการเข้าถึงสำหรับการใช้งานในเบราว์เซอร์ขณะที่ผู้ใช้อยู่

ตัวอย่างโฟลว์โดยนัยแสดงเว็บแอปก่อนและหลังการย้ายข้อมูลไปยัง บริการระบุตัวตน

ขั้นตอนรหัสการให้สิทธิ์

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

ตัวอย่างโฟลว์รหัสการให้สิทธิ์แสดงเว็บแอปก่อนและหลัง การย้ายข้อมูลไปยังบริการระบุตัวตน

ตลอดทั้งคู่มือนี้ ให้ทำตามวิธีการที่แสดงเป็นตัวหนาเพื่อเพิ่ม นำออก อัปเดต หรือแทนที่ฟังก์ชันการทำงานที่มีอยู่

การเปลี่ยนแปลงในเว็บแอปในเบราว์เซอร์

ส่วนนี้จะตรวจสอบการเปลี่ยนแปลงที่คุณจะทำกับเว็บแอปในเบราว์เซอร์เมื่อย้ายข้อมูลไปยังไลบรารี JavaScript ของ Google Identity Services

ระบุโค้ดที่ได้รับผลกระทบและทดสอบ

คุกกี้แก้ไขข้อบกพร่องจะช่วยค้นหาโค้ดที่ได้รับผลกระทบและทดสอบลักษณะการทำงานหลังการเลิกใช้งานได้

ในแอปขนาดใหญ่หรือซับซ้อน คุณอาจค้นหาโค้ดทั้งหมดที่ได้รับผลกระทบจากการ เลิกใช้งานโมดูล gapi.auth2 ได้ยาก หากต้องการบันทึกการใช้งานฟังก์ชันที่จะเลิกใช้งานในเร็วๆ นี้ลงในคอนโซล ให้ตั้งค่าG_AUTH2_MIGRATIONคุกกี้เป็น informational ไม่บังคับ: เพิ่มโคลอนตามด้วยค่าคีย์เพื่อบันทึกลงในที่เก็บข้อมูลเซสชันด้วย หลังจากลงชื่อเข้าใช้ และได้รับการตรวจสอบข้อมูลเข้าสู่ระบบ หรือส่งบันทึกที่รวบรวมไปยังแบ็กเอนด์เพื่อวิเคราะห์ในภายหลัง เช่น informational:showauth2use จะบันทึกต้นทางและ URL ไปยังคีย์พื้นที่เก็บข้อมูลเซสชันชื่อ showauth2use

หากต้องการยืนยันลักษณะการทำงานของแอปเมื่อระบบไม่โหลดโมดูล gapi.auth2 อีกต่อไป ให้ตั้งค่า คุกกี้ G_AUTH2_MIGRATION เป็น enforced ซึ่งจะช่วยให้ทดสอบ ลักษณะการทำงานหลังการเลิกใช้งานได้ก่อนวันที่บังคับใช้

ค่าคุกกี้ที่เป็นไปได้ของ G_AUTH2_MIGRATION

  • enforced อย่าโหลดโมดูล gapi.auth2
  • informational บันทึกการใช้ฟังก์ชันที่เลิกใช้งานแล้วไปยังคอนโซล JS และบันทึกลงในที่เก็บข้อมูลเซสชันเมื่อตั้งชื่อคีย์ที่ไม่บังคับ ดังนี้ informational:key-name

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

ไลบรารีและโมดูล

โมดูล gapi.auth2 จัดการการตรวจสอบสิทธิ์ของผู้ใช้สำหรับการลงชื่อเข้าใช้และโฟลว์โดยนัย สำหรับการให้สิทธิ์ ให้แทนที่โมดูลที่เลิกใช้งานแล้วนี้ รวมถึงออบเจ็กต์และ เมธอดของโมดูลด้วยไลบรารี Google Identity Services

เพิ่มไลบรารีบริการข้อมูลประจำตัวลงในเว็บแอปโดยใส่ไว้ในเอกสาร

<script src="https://accounts.google.com/gsi/client" async defer></script>

นำอินสแตนซ์ทั้งหมดของการโหลดโมดูล auth2 โดยใช้ gapi.load('auth2', function) ออก

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

คุกกี้

การให้สิทธิ์ผู้ใช้ไม่จำเป็นต้องใช้คุกกี้

ดูรายละเอียดเกี่ยวกับวิธีที่การตรวจสอบสิทธิ์ผู้ใช้ใช้คุกกี้ได้ที่การย้ายข้อมูลจาก Google Sign-In และดูการใช้คุกกี้โดยผลิตภัณฑ์และบริการอื่นๆ ของ Google ได้ที่วิธีที่ Google ใช้คุกกี้

ข้อมูลเข้าสู่ระบบ

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

หากต้องการดูการเปลี่ยนแปลงเหล่านี้ โปรดดูข้อมูลเข้าสู่ระบบตัวอย่าง

ขั้นตอนการให้สิทธิ์โดยนัย

แยกการตรวจสอบสิทธิ์และการให้สิทธิ์ของผู้ใช้โดยนำการจัดการโปรไฟล์ผู้ใช้ออกจากโฟลว์การให้สิทธิ์

นำการอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In เหล่านี้ออก

เมธอด

  • GoogleUser.getBasicProfile()
  • GoogleUser.getId()

ขั้นตอนรหัสการให้สิทธิ์

บริการข้อมูลประจำตัวจะแยกข้อมูลเข้าสู่ระบบในเบราว์เซอร์ออกเป็นโทเค็นรหัสและโทเค็นเพื่อการเข้าถึง การเปลี่ยนแปลงนี้ไม่มีผลกับข้อมูลเข้าสู่ระบบที่ได้รับผ่านการเรียกโดยตรงไปยัง ปลายทาง Google OAuth 2.0 จากแพลตฟอร์มแบ็กเอนด์ หรือผ่านไลบรารีที่ทำงานบนเซิร์ฟเวอร์ที่ปลอดภัยในแพลตฟอร์ม เช่น Google APIs Node.js Client

สถานะเซสชัน

ก่อนหน้านี้ การลงชื่อเข้าใช้ด้วย Google ช่วยให้คุณจัดการสถานะการลงชื่อเข้าใช้ของผู้ใช้ได้โดยใช้สิ่งต่อไปนี้

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

นำการอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In เหล่านี้ออก

ออบเจ็กต์

  • gapi.auth2.SignInOptions

วิธีการ

  • GoogleAuth.attachClickHandler()
  • GoogleAuth.isSignedIn()
  • GoogleAuth.isSignedIn.get()
  • GoogleAuth.isSignedIn.listen()
  • GoogleAuth.signIn()
  • GoogleAuth.signOut()
  • GoogleAuth.currentUser.get()
  • GoogleAuth.currentUser.listen()
  • GoogleUser.isSignedIn()

การกำหนดค่าไคลเอ็นต์

อัปเดตเว็บแอปเพื่อเริ่มต้นไคลเอ็นต์โทเค็นสำหรับโฟลว์รหัสการให้สิทธิ์โดยนัยหรือ

นำการอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In เหล่านี้ออก

ออบเจ็กต์

  • gapi.auth2.ClientConfig
  • gapi.auth2.OfflineAccessOptions

วิธีการ

  • gapi.auth2.getAuthInstance()
  • GoogleUser.grant()

ขั้นตอนการให้สิทธิ์โดยนัย

เพิ่มTokenClientConfigออบเจ็กต์และinitTokenClient()เรียกใช้ เพื่อกำหนดค่าเว็บแอปตามตัวอย่างในเริ่มต้นไคลเอ็นต์ โทเค็น

แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services:

ออบเจ็กต์

  • จำนวนเงิน gapi.auth2.AuthorizeConfig ด้วยบัตร TokenClientConfig

วิธีการ

  • จำนวนเงิน gapi.auth2.init() ด้วยบัตร google.accounts.oauth2.initTokenClient()

พารามิเตอร์ ได้แก่

  • gapi.auth2.AuthorizeConfig.login_hint ด้วย TokenClientConfig.login_hint
  • gapi.auth2.GoogleUser.getHostedDomain() ด้วย TokenClientConfig.hd

ขั้นตอนรหัสการให้สิทธิ์

เพิ่มออบเจ็กต์ CodeClientConfig และเรียกใช้ initCodeClient() เพื่อกำหนดค่า เว็บแอปตามตัวอย่างในเริ่มต้นไคลเอ็นต์โค้ด

เมื่อเปลี่ยนจากขั้นตอนโดยนัยเป็นขั้นตอนรหัสการให้สิทธิ์ ให้ทำดังนี้

นำ การอ้างอิงไคลเอ็นต์ JavaScript ของการลงชื่อเข้าใช้ด้วย Google ออก

ออบเจ็กต์

  • gapi.auth2.AuthorizeConfig

วิธีการ

  • gapi.auth2.init()

พารามิเตอร์ ได้แก่

  • gapi.auth2.AuthorizeConfig.login_hint
  • gapi.auth2.GoogleUser.getHostedDomain()

คำขอโทเค็น

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

ขั้นตอนการให้สิทธิ์โดยนัย

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

แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services

วิธีการ

  • จำนวนเงิน gapi.auth2.authorize() ด้วยบัตร TokenClient.requestAccessToken()
  • GoogleUser.reloadAuthResponse() ที่มี TokenClient.requestAccessToken()

เพิ่มลิงก์หรือปุ่มเพื่อเรียกใช้ requestAccessToken() เพื่อเริ่ม โฟลว์ UX แบบป๊อปอัปเพื่อขอโทเค็นเพื่อการเข้าถึง หรือเพื่อรับโทเค็นใหม่เมื่อ โทเค็นที่มีอยู่หมดอายุ

อัปเดตโค้ดเบสเป็น

  • ทริกเกอร์ขั้นตอนโทเค็น OAuth 2.0 ด้วย requestAccessToken()
  • รองรับการให้สิทธิ์แบบเพิ่มทีละรายการโดยใช้ requestAccessToken และ OverridableTokenClientConfig เพื่อแยกคำขอเดียวสำหรับขอบเขตหลายรายการ ออกเป็นคำขอที่เล็กลงหลายรายการ
  • ขอโทเค็นใหม่เมื่อโทเค็นที่มีอยู่หมดอายุหรือถูกเพิกถอน

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

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

ขั้นตอนรหัสการให้สิทธิ์

เพิ่มลิงก์หรือปุ่มเพื่อเรียกใช้ requestCode() เพื่อขอรหัสการให้สิทธิ์ จาก Google ดูตัวอย่างได้ที่ทริกเกอร์ขั้นตอนรหัส OAuth 2.0

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีตอบสนองต่อโทเค็นเพื่อการเข้าถึงที่หมดอายุหรือถูกเพิกถอนได้ที่ส่วนการจัดการโทเค็น

การจัดการโทเค็น

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

Google APIs จะแสดงรหัสสถานะ HTTP 401 Unauthorized และข้อความแสดงข้อผิดพลาด invalid_token เมื่อมีการใช้โทเค็นการเข้าถึงที่หมดอายุหรือถูกเพิกถอน ดูตัวอย่างได้ที่การตอบกลับโทเค็นไม่ถูกต้อง

โทเค็นที่หมดอายุ

โทเค็นเพื่อการเข้าถึงมีอายุสั้นและมักจะใช้ได้เพียงไม่กี่นาที

การเพิกถอนโทเค็น

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

แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services

วิธีการ

  • จำนวนเงิน getAuthInstance().disconnect() ด้วยบัตร google.accounts.oauth2.revoke()
  • จำนวนเงิน GoogleUser.disconnect() ด้วยบัตร google.accounts.oauth2.revoke()

เรียกใช้ revoke เมื่อผู้ใช้ลบบัญชีในแพลตฟอร์มของคุณ หรือ ต้องการเพิกถอนความยินยอมในการแชร์ข้อมูลกับแอปของคุณ

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

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

การลงชื่อเข้าใช้ของผู้ใช้

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

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

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

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

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

ขั้นตอนการให้สิทธิ์โดยนัย

แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services:

ออบเจ็กต์

  • จำนวนเงิน gapi.auth2.AuthorizeResponse ด้วยบัตร TokenClient.TokenResponse
  • จำนวนเงิน gapi.auth2.AuthResponse ด้วยบัตร TokenClient.TokenResponse

วิธีการ

  • GoogleUser.hasGrantedScopes() ที่มี google.accounts.oauth2.hasGrantedAllScopes()
  • GoogleUser.getGrantedScopes() ที่มี google.accounts.oauth2.hasGrantedAllScopes()

นำ การอ้างอิงไคลเอ็นต์ JavaScript ของการลงชื่อเข้าใช้ด้วย Google ออกโดยทำดังนี้

วิธีการ

  • GoogleUser.getAuthResponse()

อัปเดตเว็บแอปด้วย hasGrantedAllScopes() และ hasGrantedAnyScope() โดยทำตามตัวอย่างสิทธิ์แบบละเอียดนี้

ขั้นตอนรหัสการให้สิทธิ์

อัปเดตหรือเพิ่มปลายทางรหัสการให้สิทธิ์ลงในแพลตฟอร์มแบ็กเอนด์ โดยทำตามวิธีการในการจัดการรหัสการให้สิทธิ์

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

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

ตัวอย่างขั้นตอนการให้สิทธิ์โดยนัย

วิธีเดิม

ไลบรารีของไคลเอ็นต์ GAPI

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

gapi.auth2 โมดูลจะโหลดและใช้โดย gapi.client.init()โดยอัตโนมัติ จึงซ่อนอยู่

<!DOCTYPE html>
  <html>
    <head>
      <script src="https://apis.google.com/js/api.js"></script>
      <script>
        function start() {
          gapi.client.init({
            'apiKey': 'YOUR_API_KEY',
            'clientId': 'YOUR_CLIENT_ID',
            'scope': 'https://www.googleapis.com/auth/cloud-translation',
            'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
          }).then(function() {
            // Execute an API request which is returned as a Promise.
            // The method name language.translations.list comes from the API discovery.
            return gapi.client.language.translations.list({
              q: 'hello world',
              source: 'en',
              target: 'de',
            });
          }).then(function(response) {
            console.log(response.result.data.translations[0].translatedText);
          }, function(reason) {
            console.log('Error: ' + reason.result.error.message);
          });
        };

        // Load the JavaScript client library and invoke start afterwards.
        gapi.load('client', start);
      </script>
    </head>
    <body>
      <div id="results"></div>
    </body>
  </html>

ไลบรารีของไคลเอ็นต์ JS

OAuth 2.0 สำหรับเว็บแอปพลิเคชันฝั่งไคลเอ็นต์ที่ทํางานในเบราว์เซอร์โดยใช้ กล่องโต้ตอบป๊อปอัปเพื่อขอความยินยอมจากผู้ใช้

โหลดโมดูล gapi.auth2 ด้วยตนเอง

<!DOCTYPE html>
<html><head></head><body>
<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }

  function initClient() {
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';

    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from Google Cloud console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'clientId': 'YOUR_CLIENT_ID',
        'discoveryDocs': [discoveryUrl],
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);

      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();

      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      });
      $('#revoke-access-button').click(function() {
        revokeAccess();
      });
    });
  }

  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked "Sign out" button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }

  function revokeAccess() {
    GoogleAuth.disconnect();
  }

  function setSigninStatus() {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');
    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }

  function updateSigninStatus() {
    setSigninStatus();
  }
</script>

<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>

<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
        onload="this.onload=function(){};handleClientLoad()"
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body></html>

ปลายทาง OAuth 2.0

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

ตัวอย่างนี้แสดงการเรียกปลายทาง OAuth 2.0 ของ Google โดยตรงจากเบราว์เซอร์ของผู้ใช้ และไม่ได้ใช้โมดูล gapi.auth2 หรือไลบรารี JavaScript

<!DOCTYPE html>
<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
  var fragmentString = location.hash.substring(1);

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0) {
    localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
    if (params['state'] && params['state'] == 'try_sample_request') {
      trySampleRequest();
    }
  }

  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          'access_token=' + params['access_token']);
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.response);
        } else if (xhr.readyState === 4 && xhr.status === 401) {
          // Token invalid, so prompt for user permission.
          oauth2SignIn();
        }
      };
      xhr.send(null);
    } else {
      oauth2SignIn();
    }
  }

  /*

    *   Create form to request access token from Google's OAuth 2.0 server.
 */
function oauth2SignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);

    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                  'state': 'try_sample_request',
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};

    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }

    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>

<button onclick="trySampleRequest();">Try sample request</button>
</body></html>

วิธีใหม่

GIS เท่านั้น

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

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      var access_token;

      function initClient() {
        client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/contacts.readonly',
          callback: (tokenResponse) => {
            access_token = tokenResponse.access_token;
          },
        });
      }
      function getToken() {
        client.requestAccessToken();
      }
      function revokeToken() {
        google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
      }
      function loadCalendar() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
        xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
        xhr.send();
      }
    </script>
    <h1>Google Identity Services Authorization Token model</h1>
    <button onclick="getToken();">Get access token</button><br><br>
    <button onclick="loadCalendar();">Load Calendar</button><br><br>
    <button onclick="revokeToken();">Revoke token</button>
  </body>
</html>

async/await ของ GAPI

ตัวอย่างนี้แสดงวิธีเพิ่มไลบรารีบริการข้อมูลประจำตัวของ Google โดยใช้ รูปแบบโทเค็น นำโมดูล gapi.auth2 ออก และเรียกใช้ API โดยใช้ไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript

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

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

<!DOCTYPE html>
<html>
<head>
    <title>GAPI and GIS Example</title>
    <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
    <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoad()"></script>
</head>
<body>
    <h1>GAPI Client with GIS Authorization</h1>
    <button id="authorizeBtn" style="visibility:hidden;">Authorize and Load Events</button>
    <button id="revokeBtn" style="visibility:hidden;">Revoke Access</button>
    <div id="content"></div>

    <script>
        const YOUR_CLIENT_ID = "YOUR_CLIENT_ID";
        const YOUR_API_KEY = 'YOUR_API_KEY';
        const CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly';

        let tokenClient;
        let libsLoaded = 0;

        function gapiLoad() {
            gapi.load('client', initGapiClient);
        }

        async function initGapiClient() {
            try {
                await gapi.client.init({ apiKey: YOUR_API_KEY });
                await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
                console.log('GAPI client initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GAPI initialization failed:', err);
            }
        }

        function gisLoad() {
            try {
                tokenClient = google.accounts.oauth2.initTokenClient({
                    client_id: YOUR_CLIENT_ID,
                    scope: CALENDAR_SCOPE,
                    callback: '', // Will be set dynamically
                    error_callback: handleGisError,
                });
                console.log('GIS TokenClient initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GIS initialization failed:', err);
            }
        }

        function checkAllLoaded() {
            libsLoaded++;
            if (libsLoaded === 2) {
                document.getElementById('authorizeBtn').style.visibility = 'visible';
                document.getElementById('revokeBtn').style.visibility = 'visible';
                document.getElementById('authorizeBtn').onclick = makeApiCall;
                document.getElementById('revokeBtn').onclick = revokeAccess;
                console.log('Ready to authorize.');
            }
        }

        function handleGisError(err) {
            console.error('GIS Error:', err);
            let message = 'An error occurred during authorization.';
            if (err && err.type === 'popup_failed_to_open') {
                message = 'Failed to open popup. Please disable popup blockers.';
            } else if (err && err.type === 'popup_closed') {
                message = 'Authorization popup was closed.';
            }
            document.getElementById('content').textContent = message;
        }

        function handleError(message, error) {
            console.error(message, error);
            document.getElementById('content').textContent = `${message} ${error.message || JSON.stringify(error)}`;
        }

        async function makeApiCall() {
            document.getElementById('content').textContent = 'Processing...';
            try {
                let token = gapi.client.getToken();
                if (!token || !token.access_token) {
                    console.log('No token, fetching one...');
                    await getToken();
                }

                console.log('Calling Calendar API...');
                const response = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                displayEvents(response.result);
            } catch (err) {
                console.error('API call failed:', err);
                const errorInfo = err.result && err.result.error;
                if (errorInfo && (errorInfo.code === 401 || (errorInfo.code === 403 && errorInfo.status === "PERMISSION_DENIED"))) {
                    console.log('Auth error on API call, refreshing token...');
                    try {
                        await getToken({ prompt: 'consent' }); // Force refresh
                        const retryResponse = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                        displayEvents(retryResponse.result);
                    } catch (refreshErr) {
                        handleError('Failed to refresh token or retry API call:', refreshErr);
                    }
                } else {
                    handleError('Error loading events:', err.result ? err.result.error : err);
                }
            }
        }

        async function getToken(options = { prompt: '' }) {
            return new Promise((resolve, reject) => {
                if (!tokenClient) return reject(new Error("GIS TokenClient not initialized."));
                tokenClient.callback = (tokenResponse) => {
                    if (tokenResponse.error) {
                        reject(new Error(`Token Error: ${tokenResponse.error} - ${tokenResponse.error_description}`));
                    } else {
                        console.log('Token acquired.');
                        resolve(tokenResponse);
                    }
                };
                tokenClient.requestAccessToken(options);
            });
        }

        function displayEvents(result) {
            const events = result.items;
            if (events && events.length > 0) {
                let eventList = '<h3>Upcoming Events:</h3><ul>' + events.map(event =>
                    `<li>${event.summary} (${event.start.dateTime || event.start.date})</li>`
                ).join('') + '</ul>';
                document.getElementById('content').innerHTML = eventList;
            } else {
                document.getElementById('content').textContent = 'No upcoming events found.';
            }
        }

        function revokeAccess() {
            const token = gapi.client.getToken();
            if (token && token.access_token) {
                google.accounts.oauth2.revoke(token.access_token, () => {
                    console.log('Access revoked.');
                    document.getElementById('content').textContent = 'Access has been revoked.';
                    gapi.client.setToken(null);
                });
            } else {
                document.getElementById('content').textContent = 'No token to revoke.';
            }
        }
    </script>
</body>
</html>

การเรียกกลับของ GAPI

ตัวอย่างนี้แสดงวิธีเพิ่มไลบรารีบริการข้อมูลประจำตัวของ Google โดยใช้ รูปแบบโทเค็น นำโมดูล gapi.auth2 ออก และเรียกใช้ API โดยใช้ไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript

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

ผู้ใช้ควรจะกดปุ่ม "แสดงปฏิทิน" เมื่อหน้าเว็บโหลดเป็นครั้งแรก และอีกครั้งเมื่อต้องการรีเฟรชข้อมูลปฏิทิน

<!DOCTYPE html>
<html>
<head>
  <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
</head>
<body>
  <h1>GAPI with GIS callbacks</h1>
  <button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
  <button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>
  <script>
    let tokenClient;
    let gapiInited;
    let gisInited;

    document.getElementById("showEventsBtn").style.visibility="hidden";
    document.getElementById("revokeBtn").style.visibility="hidden";

    function checkBeforeStart() {
       if (gapiInited && gisInited){
          // Start only when both gapi and gis are initialized.
          document.getElementById("showEventsBtn").style.visibility="visible";
          document.getElementById("revokeBtn").style.visibility="visible";
       }
    }

    function gapiInit() {
      gapi.client.init({
        // NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
      })
      .then(function() {  // Load the Calendar API discovery document.
        gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
        gapiInited = true;
        checkBeforeStart();
      });
    }

    function gapiLoad() {
        gapi.load('client', gapiInit)
    }

    function gisInit() {
     tokenClient = google.accounts.oauth2.initTokenClient({
                client_id: 'YOUR_CLIENT_ID',
                scope: 'https://www.googleapis.com/auth/calendar.readonly',
                callback: '',  // defined at request time
            });
      gisInited = true;
      checkBeforeStart();
    }

    function showEvents() {

      tokenClient.callback = (resp) => {
        if (resp.error !== undefined) {
          throw(resp);
        }
        // GIS has automatically updated gapi.client with the newly issued access token.
        console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));

        gapi.client.calendar.events.list({ 'calendarId': 'primary' })
        .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
        .catch(err => console.log(err));

        document.getElementById("showEventsBtn").innerText = "Refresh Calendar";
      }

      // Conditionally ask users to select the Google Account they'd like to use,
      // and explicitly obtain their consent to fetch their Calendar.
      // NOTE: To request an access token a user gesture is necessary.
      if (gapi.client.getToken() === null) {
        // Prompt the user to select a Google Account and asked for consent to share their data
        // when establishing a new session.
        tokenClient.requestAccessToken({prompt: 'consent'});
      } else {
        // Skip display of account chooser and consent dialog for an existing session.
        tokenClient.requestAccessToken({prompt: ''});
      }
    }

    function revokeToken() {
      let cred = gapi.client.getToken();
      if (cred !== null) {
        google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
        gapi.client.setToken('');
        document.getElementById("showEventsBtn").innerText = "Show Calendar";
      }
    }
  </script>
</body>
</html>

ตัวอย่างขั้นตอนรหัสการให้สิทธิ์

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

วิธีเดิม

เว็บแอปฝั่งเซิร์ฟเวอร์

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

<!DOCTYPE html>
<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
    <script>
      function start() {
        gapi.load('auth2', function() {
          auth2 = gapi.auth2.init({
            client_id: 'YOUR_CLIENT_ID',
            api_key: 'YOUR_API_KEY',
            discovery_docs: ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
            // Scopes to request in addition to 'profile' and 'email'
            scope: 'https://www.googleapis.com/auth/cloud-translation',
          });
        });
      }
      function signInCallback(authResult) {
        if (authResult['code']) {
          console.log("sending AJAX request");
          // Send authorization code obtained from Google to backend platform
          $.ajax({
            type: 'POST',
            url: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
            // Always include an X-Requested-With header to protect against CSRF attacks.
            headers: {
              'X-Requested-With': 'XMLHttpRequest'
            },
            contentType: 'application/octet-stream; charset=utf-8',
            success: function(result) {
              console.log(result);
            },
            processData: false,
            data: authResult['code']
          });
        } else {
          console.log('error: failed to obtain authorization code')
        }
      }
    </script>
  </head>
  <body>
    <button id="signinButton">Sign In With Google</button>
    <script>
      $('#signinButton').click(function() {
        // Obtain an authorization code from Google
        auth2.grantOfflineAccess().then(signInCallback);
      });
    </script>
  </body>
</html>

HTTP/REST โดยใช้การเปลี่ยนเส้นทาง

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

/\*
 \* Create form to request access token from Google's OAuth 2.0 server.
 \*/
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
  // Create &lt;form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);
  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {'client\_id': 'YOUR_CLIENT_ID',
                'redirect\_uri': 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
                'response\_type': 'token',
                'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                'include\_granted\_scopes': 'true',
                'state': 'pass-through value'};
  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

วิธีใหม่

UX ของป๊อปอัป GIS

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

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly',
          ux_mode: 'popup',
          callback: (response) => {
            var code_receiver_uri = 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI',
            // Send auth code to your backend platform
            const xhr = new XMLHttpRequest();
            xhr.open('POST', code_receiver_uri, true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            xhr.onload = function() {
              console.log('Signed in as: ' + xhr.responseText);
            };
            xhr.send('code=' + response.code);
            // After receipt, the code is exchanged for an access token and
            // refresh token, and the platform then updates this web app
            // running in user's browser with the requested calendar info.
          },
        });
      }
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

UX การเปลี่ยนเส้นทางของ GIS

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

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/photoslibrary.readonly',
          ux_mode: 'redirect',
          redirect_uri: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI'
        });
      }
      // Request an access token
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

ไลบรารี JavaScript

Google Identity Services คือไลบรารี JavaScript เดียวที่ใช้สำหรับการตรวจสอบสิทธิ์และการให้สิทธิ์ผู้ใช้ ซึ่งรวมและแทนที่ฟีเจอร์และฟังก์ชันที่พบในไลบรารีและโมดูลต่างๆ ดังนี้

สิ่งที่ต้องทำเมื่อย้ายข้อมูลไปยังบริการ Identity

ไลบรารี JS ที่มีอยู่ ไลบรารี JS ใหม่ หมายเหตุ
apis.google.com/js/api.js accounts.google.com/gsi/client เพิ่มไลบรารีใหม่และทำตามโฟลว์โดยนัย
apis.google.com/js/client.js accounts.google.com/gsi/client เพิ่มไลบรารีใหม่และโฟลว์รหัสการให้สิทธิ์

ข้อมูลอ้างอิงฉบับย่อของไลบรารี

การเปรียบเทียบออบเจ็กต์และเมธอดระหว่างไลบรารี เก่า Google Sign-In JavaScript client กับไลบรารี ใหม่ Google Identity Services และหมายเหตุพร้อมข้อมูลเพิ่มเติมและการดำเนินการที่ต้องทำระหว่างการย้ายข้อมูล

เก่า ใหม่ หมายเหตุ
ออบเจ็กต์ GoogleAuth และเมธอดที่เกี่ยวข้อง
GoogleAuth.attachClickHandler() นำออก
GoogleAuth.currentUser.get() นำออก
GoogleAuth.currentUser.listen() นำออก
GoogleAuth.disconnect() google.accounts.oauth2.revoke แทนที่ของเก่าด้วยของใหม่ การเพิกถอนอาจเกิดขึ้นได้จาก https://myaccount.google.com/permissions
GoogleAuth.grantOfflineAccess() หากต้องการนำออก ให้ทำตามขั้นตอนรหัสการให้สิทธิ์
GoogleAuth.isSignedIn.get() นำออก
GoogleAuth.isSignedIn.listen() นำออก
GoogleAuth.signIn() นำออก
GoogleAuth.signOut() นำออก
GoogleAuth.then() นำออก
ออบเจ็กต์ GoogleUser และเมธอดที่เกี่ยวข้อง
GoogleUser.disconnect() google.accounts.id.revoke แทนที่ของเก่าด้วยของใหม่ การเพิกถอนอาจเกิดขึ้นได้จาก https://myaccount.google.com/permissions
GoogleUser.getAuthResponse() requestCode() or requestAccessToken() แทนที่ของเก่าด้วยของใหม่
GoogleUser.getBasicProfile() นำออก โปรดใช้โทเค็นรหัสแทน ดูการย้ายข้อมูลจากการลงชื่อเข้าใช้ด้วย Google
GoogleUser.getGrantedScopes() hasGrantedAnyScope() แทนที่ของเก่าด้วยของใหม่
GoogleUser.getHostedDomain() นำออก
GoogleUser.getId() นำออก
GoogleUser.grantOfflineAccess() หากต้องการนำออก ให้ทำตามขั้นตอนรหัสการให้สิทธิ์
GoogleUser.grant() นำออก
GoogleUser.hasGrantedScopes() hasGrantedAnyScope() แทนที่ของเก่าด้วยของใหม่
GoogleUser.isSignedIn() นำออก
GoogleUser.reloadAuthResponse() requestAccessToken() นำโทเค็นเก่าออก เรียกใช้โทเค็นใหม่เพื่อแทนที่โทเค็นเพื่อการเข้าถึงที่หมดอายุหรือถูกเพิกถอน
ออบเจ็กต์ gapi.auth2 และเมธอดที่เกี่ยวข้อง
ออบเจ็กต์ gapi.auth2.AuthorizeConfig TokenClientConfig หรือ CodeClientConfig แทนที่ของเก่าด้วยของใหม่
ออบเจ็กต์ gapi.auth2.AuthorizeResponse นำออก
ออบเจ็กต์ gapi.auth2.AuthResponse นำออก
gapi.auth2.authorize() requestCode() or requestAccessToken() แทนที่ของเก่าด้วยของใหม่
gapi.auth2.ClientConfig() TokenClientConfig หรือ CodeClientConfig แทนที่ของเก่าด้วยของใหม่
gapi.auth2.getAuthInstance() นำออก
gapi.auth2.init() initTokenClient() or initCodeClient() แทนที่ของเก่าด้วยของใหม่
ออบเจ็กต์ gapi.auth2.OfflineAccessOptions นำออก
ออบเจ็กต์ gapi.auth2.SignInOptions นำออก
ออบเจ็กต์ gapi.signin2 และเมธอดที่เกี่ยวข้อง
gapi.signin2.render() นำออก การโหลด HTML DOM ขององค์ประกอบ g_id_signin หรือการเรียก JS ไปยัง google.accounts.id.renderButton จะทริกเกอร์การลงชื่อเข้าใช้บัญชี Google ของผู้ใช้

ตัวอย่างข้อมูลเข้าสู่ระบบ

ข้อมูลเข้าสู่ระบบที่มีอยู่

ไลบรารีแพลตฟอร์ม Google Sign-In, ไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript หรือการเรียกปลายทาง Google OAuth 2.0 โดยตรงจะแสดงผล ทั้งโทเค็นการเข้าถึง OAuth 2.0 และโทเค็นรหัส OpenID Connect ในการตอบกลับเดียว

ตัวอย่างการตอบกลับที่มีทั้ง access_token และ id_token

  {
    "token_type": "Bearer",
    "access_token": "ya29.A0ARrdaM-SmArZaCIh68qXsZSzyeU-8mxhQERHrP2EXtxpUuZ-3oW8IW7a6D2J6lRnZrRj8S6-ZcIl5XVEqnqxq5fuMeDDH_6MZgQ5dgP7moY-yTiKR5kdPm-LkuPM-mOtUsylWPd1wpRmvw_AGOZ1UUCa6UD5Hg",
    "scope": "https://www.googleapis.com/auth/calendar.readonly",
    "login_hint": "AJDLj6I2d1RH77cgpe__DdEree1zxHjZJr4Q7yOisoumTZUmo5W2ZmVFHyAomUYzLkrluG-hqt4RnNxrPhArd5y6p8kzO0t8xIfMAe6yhztt6v2E-_Bb4Ec3GLFKikHSXNh5bI-gPrsI",
    "expires_in": 3599,
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjkzNDFhYmM0MDkyYjZmYzAzOGU0MDNjOTEwMjJkZDNlNDQ1MzliNTYiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTE3NzI2NDMxNjUxOTQzNjk4NjAwIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IkJBSW55TjN2MS1ZejNLQnJUMVo0ckEiLCJuYW1lIjoiQnJpYW4gRGF1Z2hlcnR5IiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hLS9BT2gxNEdnenAyTXNGRGZvbVdMX3VDemRYUWNzeVM3ZGtxTE5ybk90S0QzVXNRPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkJyaWFuIiwiZmFtaWx5X25hbWUiOiJEYXVnaGVydHkiLCJsb2NhbGUiOiJlbiIsImlhdCI6MTYzODk5MTYzOCwiZXhwIjoxNjM4OTk1MjM4LCJqdGkiOiI5YmRkZjE1YWFiNzE2ZDhjYmJmNDYwMmM1YWM3YzViN2VhMDQ5OTA5In0.K3EA-3Adw5HA7O8nJVCsX1HmGWxWzYk3P7ViVBb4H4BoT2-HIgxKlx1mi6jSxIUJGEekjw9MC-nL1B9Asgv1vXTMgoGaNna0UoEHYitySI23E5jaMkExkTSLtxI-ih2tJrA2ggfA9Ekj-JFiMc6MuJnwcfBTlsYWRcZOYVw3QpdTZ_VYfhUu-yERAElZCjaAyEXLtVQegRe-ymScra3r9S92TA33ylMb3WDTlfmDpWL0CDdDzby2asXYpl6GQ7SdSj64s49Yw6mdGELZn5WoJqG7Zr2KwIGXJuSxEo-wGbzxNK-mKAiABcFpYP4KHPEUgYyz3n9Vqn2Tfrgp-g65BQ",
    "session_state": {
      "extraQueryParams": {
        "authuser": "0"
      }
    },
    "first_issued_at": 1638991637982,
    "expires_at": 1638995236982,
    "idpId": "google"
  }

ข้อมูลเข้าสู่ระบบของ Google Identity Services

ไลบรารีบริการ Google Identity จะแสดงผลดังนี้

  • โทเค็นเพื่อการเข้าถึงเมื่อใช้เพื่อการให้สิทธิ์

    {
      "access_token": "ya29.A0ARrdaM_LWSO-uckLj7IJVNSfnUityT0Xj-UCCrGxFQdxmLiWuAosnAKMVQ2Z0LLqeZdeJii3TgULp6hR_PJxnInBOl8UoUwWoqsrGQ7-swxgy97E8_hnzfhrOWyQBmH6zs0_sUCzwzhEr_FAVqf92sZZHphr0g",
      "token_type": "Bearer",
      "expires_in": 3599,
      "scope": "https://www.googleapis.com/auth/calendar.readonly"
    }
    
  • หรือโทเค็นรหัสเมื่อใช้สำหรับการตรวจสอบสิทธิ์

    {
      "clientId": "538344653255-758c5h5isc45vgk27d8h8deabovpg6to.apps.googleusercontent.com",
      "credential": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxODkyZWI0OWQ3ZWY5YWRmOGIyZTE0YzA1Y2EwZDAzMjcxNGEyMzciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2MzkxNTcyNjQsImF1ZCI6IjUzODM0NDY1MzI1NS03NThjNWg1aXNjNDV2Z2syN2Q4aDhkZWFib3ZwZzZ0by5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjExNzcyNjQzMTY1MTk0MzY5ODYwMCIsIm5vbmNlIjoiZm9vYmFyIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwibmFtZSI6IkJyaWFuIERhdWdoZXJ0eSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQU9oMTRHZ3pwMk1zRkRmb21XTF91Q3pkWFFjc3lTN2RrcUxOcm5PdEtEM1VzUT1zOTYtYyIsImdpdmVuX25hbWUiOiJCcmlhbiIsImZhbWlseV9uYW1lIjoiRGF1Z2hlcnR5IiwiaWF0IjoxNjM5MTU3NTY0LCJleHAiOjE2MzkxNjExNjQsImp0aSI6IjRiOTVkYjAyZjU4NDczMmUxZGJkOTY2NWJiMWYzY2VhYzgyMmI0NjUifQ.Cr-AgMsLFeLurnqyGpw0hSomjOCU4S3cU669Hyi4VsbqnAV11zc_z73o6ahe9Nqc26kPVCNRGSqYrDZPfRyTnV6g1PIgc4Zvl-JBuy6O9HhClAK1HhMwh1FpgeYwXqrng1tifmuotuLQnZAiQJM73Gl-J_6s86Buo_1AIx5YAKCucYDUYYdXBIHLxrbALsA5W6pZCqqkMbqpTWteix-G5Q5T8LNsfqIu_uMBUGceqZWFJALhS9ieaDqoxhIqpx_89QAr1YlGu_UO6R6FYl0wDT-nzjyeF5tonSs3FHN0iNIiR3AMOHZu7KUwZaUdHg4eYkU-sQ01QNY_11keHROCRQ",
      "select_by": "user"
    }
    

การตอบกลับโทเค็นไม่ถูกต้อง

ตัวอย่างการตอบกลับจาก Google เมื่อพยายามส่งคำขอ API โดยใช้โทเค็นเพื่อการเข้าถึงที่ หมดอายุ ถูกเพิกถอน หรือไม่ถูกต้อง

ส่วนหัวการตอบกลับ HTTP

  www-authenticate: Bearer realm="https://accounts.google.com/", error="invalid_token"

เนื้อหาการตอบกลับ

  {
    "error": {
      "code": 401,
      "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
      "errors": [
        {
          "message": "Invalid Credentials",
          "domain": "global",
          "reason": "authError",
          "location": "Authorization",
          "locationType": "header"
        }
      ],
      "status": "UNAUTHENTICATED"
    }
  }