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

ภาพรวม

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

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

การปฏิบัติตามคู่มือนี้จะให้คุณ

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

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

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

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

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

ตรวจสอบเว็บแอปเพื่อระบุประเภทของขั้นตอนการให้สิทธิ์ที่ใช้งานอยู่ในปัจจุบัน

การบ่งชี้ที่เว็บแอปใช้ขั้นตอนการดำเนินการโดยนัย ดังนี้

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

  • การติดตั้งใช้งานขึ้นอยู่กับปัจจัยต่อไปนี้

  • แอปจะทำงานทั้งในเบราว์เซอร์ของผู้ใช้และในแพลตฟอร์มแบ็กเอนด์

  • แพลตฟอร์มแบ็กเอนด์โฮสต์ปลายทางของรหัสการให้สิทธิ์

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

  • โทเค็นการรีเฟรชได้รับการจัดการและจัดเก็บโดยแพลตฟอร์มแบ็กเอนด์ของคุณ

ในบางกรณี ฐานของโค้ดอาจรองรับทั้ง 2 ขั้นตอน

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ในแอปที่มีขนาดใหญ่หรือซับซ้อน อาจเป็นเรื่องยากที่จะหาโค้ดทั้งหมดที่ได้รับผลกระทบจากการเลิกใช้งานโมดูล 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 Identity Services จะแทนที่การใช้งานโมดูล gapi.auth2 คุณสามารถใช้โมดูล gapi.client ได้อย่างปลอดภัยจากไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript และใช้ประโยชน์จากการสร้างเมธอด JS ที่เรียกใช้ได้แบบอัตโนมัติจากเอกสารการค้นพบ การรวมการเรียก API หลายรายการเข้าด้วยกัน และฟังก์ชันการจัดการ CORS

คุกกี้

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

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

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

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

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

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

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

ลบข้อมูลอ้างอิงไคลเอ็นต์ Google Sign-In JavaScript เหล่านี้

วิธีการ

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

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

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

สถานะเซสชัน

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

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

ลบข้อมูลอ้างอิงไคลเอ็นต์ Google Sign-In JavaScript เหล่านี้

ออบเจ็กต์:

  • 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()

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

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

ลบข้อมูลอ้างอิงไคลเอ็นต์ Google Sign-In JavaScript เหล่านี้

ออบเจ็กต์:

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

วิธีการ:

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

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

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

แทนที่ การอ้างอิงไคลเอ็นต์ Google Sign-In JavaScript ด้วย 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 Sign-In

ออบเจ็กต์:

  • gapi.auth2.AuthorizeConfig

วิธีการ:

  • gapi.auth2.init()

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

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

คำขอโทเค็น

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

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

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

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

วิธีการ:

  • gapi.auth2.authorize() ร่วมกับ TokenClient.requestAccessToken()
  • GoogleUser.reloadAuthResponse() กับ TokenClient.requestAccessToken()

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

อัปเดตฐานของโค้ดเป็น

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

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

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

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

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

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

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

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

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

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

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

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

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

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

วิธีการ:

  • getAuthInstance().disconnect() ร่วมกับ google.accounts.oauth2.revoke()
  • GoogleUser.disconnect() ร่วมกับ google.accounts.oauth2.revoke()

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

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

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

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

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

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

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

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

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

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

แทนที่ การอ้างอิงไคลเอ็นต์ Google Sign-In JavaScript ด้วย 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 Sign-In ออก ดังนี้

วิธีการ:

  • 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 API 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 Identity Service ที่ใช้โมเดลโทเค็นและกล่องโต้ตอบป๊อปอัปสำหรับความยินยอมของผู้ใช้ ข้อมูลนี้มีไว้เพื่อแสดงตัวอย่างจำนวนขั้นตอนขั้นต่ำที่จำเป็นในการกำหนดค่าไคลเอ็นต์ คำขอ และรับโทเค็นเพื่อการเข้าถึง รวมถึงการเรียกใช้ 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>

GAPI async/await

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

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

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

<!DOCTYPE html>
<html>
<head></head>
<body>
  <h1>GAPI with GIS async/await</h1>
  <button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
  <button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>

  <script>

    const gapiLoadPromise = new Promise((resolve, reject) => {
      gapiLoadOkay = resolve;
      gapiLoadFail = reject;
    });
    const gisLoadPromise = new Promise((resolve, reject) => {
      gisLoadOkay = resolve;
      gisLoadFail = reject;
    });

    var tokenClient;

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

      // First, load and initialize the gapi.client
      await gapiLoadPromise;
      await new Promise((resolve, reject) => {
        // NOTE: the 'auth2' module is no longer loaded.
        gapi.load('client', {callback: resolve, onerror: reject});
      });
      await 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');
      });

      // Now load the GIS client
      await gisLoadPromise;
      await new Promise((resolve, reject) => {
        try {
          tokenClient = google.accounts.oauth2.initTokenClient({
              client_id: 'YOUR_CLIENT_ID',
              scope: 'https://www.googleapis.com/auth/calendar.readonly',
              prompt: 'consent',
              callback: '',  // defined at request time in await/promise scope.
          });
          resolve();
        } catch (err) {
          reject(err);
        }
      });

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

    async function getToken(err) {

      if (err.result.error.code == 401 || (err.result.error.code == 403) &&
          (err.result.error.status == "PERMISSION_DENIED")) {

        // The access token is missing, invalid, or expired, prompt for user consent to obtain one.
        await new Promise((resolve, reject) => {
          try {
            // Settle this promise in the response callback for requestAccessToken()
            tokenClient.callback = (resp) => {
              if (resp.error !== undefined) {
                reject(resp);
              }
              // GIS has automatically updated gapi.client with the newly issued access token.
              console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));
              resolve(resp);
            };
            tokenClient.requestAccessToken();
          } catch (err) {
            console.log(err)
          }
        });
      } else {
        // Errors unrelated to authorization: server errors, exceeding quota, bad requests, and so on.
        throw new Error(err);
      }
    }

    function showEvents() {

      // Try to fetch a list of Calendar events. If a valid access token is needed,
      // prompt to obtain one and then retry the original request.
      gapi.client.calendar.events.list({ 'calendarId': 'primary' })
      .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
      .catch(err  => getToken(err))  // for authorization errors obtain an access token
      .then(retry => gapi.client.calendar.events.list({ 'calendarId': 'primary' }))
      .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
      .catch(err  => console.log(err)); // cancelled by user, timeout, etc.
    }

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

  </script>

  <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoadOkay()" onerror="gapiLoadFail(event)"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoadOkay()" onerror="gisLoadFail(event)"></script>

</body>
</html>

โค้ดเรียกกลับ GAPI

ตัวอย่างนี้แสดงวิธีเพิ่มไลบรารี Google Identity Service โดยใช้โมเดลโทเค็น นำโมดูล 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 Identity Service โดยใช้โมเดลรหัสการให้สิทธิ์ กล่องโต้ตอบป๊อปอัปสำหรับความยินยอมของผู้ใช้และตัวแฮนเดิลเรียกกลับเพื่อรับรหัสการให้สิทธิ์จาก 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 คือไลบรารี JavaScript แบบเดียวที่ใช้สำหรับการตรวจสอบสิทธิ์และการให้สิทธิ์ผู้ใช้ ซึ่งรวมและแทนที่ฟีเจอร์และฟังก์ชันการทำงานที่พบในไลบรารีและโมดูลต่างๆ ดังนี้

สิ่งที่ต้องทําเมื่อย้ายข้อมูลไปยัง Identity Services

ไลบรารี JS ที่มีอยู่ ไลบรารี JS ใหม่ Notes
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 เก่า กับไลบรารี Google Identity Services ใหม่ และหมายเหตุที่มีข้อมูลและการดำเนินการเพิ่มเติมที่ต้องทำระหว่างการย้ายข้อมูล

เก่า ใหม่ Notes
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 Sign-In
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 Auth 2.0 จะส่งคืนทั้งโทเค็นเพื่อการเข้าถึง OAuth 2.0 และโทเค็นรหัส Connect ID ในการตอบสนองเดียว

ตัวอย่างการตอบกลับที่มีทั้ง 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 Services จะแสดงข้อมูลต่อไปนี้

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

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