ภาพรวม
Google มีไลบรารี JavaScript หลายรายการเพื่อรับโทเค็นเพื่อการเข้าถึงต่อผู้ใช้เพื่อเรียกใช้ Google API ดังนี้
คู่มือนี้มีวิธีการย้ายข้อมูลจากไลบรารีเหล่านี้ไปยังไลบรารี Google Identity Services
การทำตามคำแนะนำนี้จะช่วยให้คุณทำสิ่งต่อไปนี้ได้
- แทนที่ Platform Library ที่เลิกใช้งานแล้วด้วย Identity Services Library และ
- หากใช้ไลบรารีของไคลเอ็นต์ API ให้นำโมดูล
gapi.auth2ที่เลิกใช้แล้ว เมธอดและออบเจ็กต์ของโมดูลออก แล้วแทนที่ด้วยรายการที่เทียบเท่ากับ Identity Services
โปรดอ่านภาพรวมและวิธีที่การให้สิทธิ์ของผู้ใช้ทำงานเพื่อดูคำอธิบายเกี่ยวกับสิ่งที่เปลี่ยนแปลงในไลบรารี JavaScript ของบริการระบุตัวตน และตรวจสอบคำศัพท์และแนวคิดสำคัญ
หากคุณกำลังมองหาการตรวจสอบสิทธิ์สำหรับการลงชื่อสมัครใช้และลงชื่อเข้าใช้ของผู้ใช้ โปรดดูการย้ายข้อมูลจาก Google Sign-In แทน
ระบุขั้นตอนการให้สิทธิ์
ขั้นตอนการให้สิทธิ์ผู้ใช้มี 2 แบบ ได้แก่ แบบโดยนัยและแบบรหัสการให้สิทธิ์
ตรวจสอบเว็บแอปเพื่อระบุประเภทโฟลว์การให้สิทธิ์ที่ใช้
ข้อบ่งชี้ว่าเว็บแอปของคุณใช้โฟลว์โดยนัย
- เว็บแอปของคุณใช้เบราว์เซอร์อย่างเดียวโดยไม่มีแพลตฟอร์มแบ็กเอนด์
- ผู้ใช้ต้องอยู่ต่อหน้าอุปกรณ์เพื่อเรียกใช้ Google API โดยแอปของคุณจะใช้เฉพาะโทเค็นการเข้าถึง และไม่จำเป็นต้องใช้โทเค็นการรีเฟรช
- เว็บแอปโหลด
apis.google.com/js/api.js - การติดตั้งใช้งานของคุณอิงตาม OAuth 2.0 สำหรับเว็บแอปพลิเคชันฝั่งไคลเอ็นต์
- แอปของคุณใช้โมดูล
gapi.clientหรือgapi.auth2ที่อยู่ในไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript
ข้อบ่งชี้ว่าเว็บแอปของคุณใช้ขั้นตอนรหัสการให้สิทธิ์
การติดตั้งใช้งานของคุณอิงตามสิ่งต่อไปนี้
แอปของคุณจะทำงานทั้งในเบราว์เซอร์ของผู้ใช้และบนแพลตฟอร์มแบ็กเอนด์
แพลตฟอร์มแบ็กเอนด์ของคุณโฮสต์ปลายทางรหัสการให้สิทธิ์
แพลตฟอร์มแบ็กเอนด์ของคุณเรียกใช้ Google API ในนามของผู้ใช้โดยไม่ต้องให้ผู้ใช้อยู่ในระบบ ซึ่งเรียกอีกอย่างว่าโหมดออฟไลน์
แพลตฟอร์มแบ็กเอนด์ของคุณเป็นผู้จัดการและจัดเก็บโทเค็นการรีเฟรช
ในบางกรณี ฐานโค้ดอาจรองรับทั้ง 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.auth2informationalบันทึกการใช้ฟังก์ชันที่เลิกใช้งานแล้วไปยังคอนโซล 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 ช่วยให้คุณจัดการสถานะการลงชื่อเข้าใช้ของผู้ใช้ได้โดยใช้สิ่งต่อไปนี้
- ตัวแฮนเดิลการเรียกกลับสำหรับการตรวจสอบสถานะเซสชันของผู้ใช้
- Listeners สำหรับเหตุการณ์และการเปลี่ยนแปลงสถานะการลงชื่อเข้าใช้สำหรับบัญชี 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.ClientConfiggapi.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_hintgapi.auth2.GoogleUser.getHostedDomain()ด้วยTokenClientConfig.hd
ขั้นตอนรหัสการให้สิทธิ์
เพิ่มออบเจ็กต์ CodeClientConfig และเรียกใช้ initCodeClient() เพื่อกำหนดค่า เว็บแอปตามตัวอย่างในเริ่มต้นไคลเอ็นต์โค้ด
เมื่อเปลี่ยนจากขั้นตอนโดยนัยเป็นขั้นตอนรหัสการให้สิทธิ์ ให้ทำดังนี้
นำ การอ้างอิงไคลเอ็นต์ JavaScript ของการลงชื่อเข้าใช้ด้วย Google ออก
ออบเจ็กต์
gapi.auth2.AuthorizeConfig
วิธีการ
gapi.auth2.init()
พารามิเตอร์ ได้แก่
gapi.auth2.AuthorizeConfig.login_hintgapi.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 <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 เดียวที่ใช้สำหรับการตรวจสอบสิทธิ์และการให้สิทธิ์ผู้ใช้ ซึ่งรวมและแทนที่ฟีเจอร์และฟังก์ชันที่พบในไลบรารีและโมดูลต่างๆ ดังนี้
- ไคลเอ็นต์ JavaScript ของการลงชื่อเข้าใช้ด้วย Google และ
- ไลบรารีของไคลเอ็นต์ Google API สำหรับ 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" } }