ภาพรวม
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.auth2
- informationalบันทึกการใช้ฟังก์ชันที่เลิกใช้งานแล้วไปยังคอนโซล JS และบันทึกลงในที่เก็บข้อมูลเซสชันเมื่อตั้งชื่อคีย์ที่ไม่บังคับ ดังนี้- informational:key-name
เราขอแนะนำให้คุณตั้งค่าคุกกี้นี้ในเครื่องก่อน ระหว่างการพัฒนาและการทดสอบ ก่อนที่จะนำไปใช้ในสภาพแวดล้อมการใช้งานจริง เพื่อลดผลกระทบต่อผู้ใช้
ไลบรารีและโมดูล
โมดูล gapi.auth2 จัดการการตรวจสอบสิทธิ์ของผู้ใช้สำหรับการลงชื่อเข้าใช้และโฟลว์โดยนัย
สำหรับการให้สิทธิ์ ให้แทนที่โมดูลที่เลิกใช้งานแล้วนี้ รวมถึงออบเจ็กต์และ
เมธอดของโมดูลด้วยไลบรารี Google Identity Services
เพิ่มไลบรารีบริการข้อมูลประจำตัวลงในเว็บแอปโดยใส่ไว้ในเอกสาร
<script src="https://accounts.google.com/gsi/client" async defer></script>
นำอินสแตนซ์ทั้งหมดของการโหลดโมดูล auth2 โดยใช้ gapi.load('auth2',
function) ออก
ไลบรารีบริการระบุตัวตนของ Google จะแทนที่การใช้โมดูล gapi.auth2
คุณสามารถใช้โมดูล gapi.client จากไลบรารีของไคลเอ็นต์ Google API
สำหรับ JavaScript ต่อไปได้อย่างปลอดภัย และใช้ประโยชน์จากการสร้างอัตโนมัติ
ของเมธอด JS ที่เรียกใช้ได้จากเอกสารการค้นพบ การจัดกลุ่มการเรียก API หลายรายการ
 และฟังก์ชันการจัดการ CORS
คุกกี้
การให้สิทธิ์ผู้ใช้ไม่จำเป็นต้องใช้คุกกี้
ดูรายละเอียดเกี่ยวกับวิธีที่การตรวจสอบสิทธิ์ผู้ใช้ใช้คุกกี้ได้ที่การย้ายข้อมูลจาก Google Sign-In และดูการใช้คุกกี้โดยผลิตภัณฑ์และบริการอื่นๆ ของ Google ได้ที่วิธีที่ Google ใช้คุกกี้
ข้อมูลเข้าสู่ระบบ
บริการระบุตัวตนของ Google จะแยกการตรวจสอบสิทธิ์และการให้สิทธิ์ของผู้ใช้ออกเป็น 2 การดำเนินการที่แตกต่างกัน และข้อมูลเข้าสู่ระบบของผู้ใช้จะแยกกัน โดยโทเค็นรหัสที่ใช้ ระบุผู้ใช้จะแสดงแยกจากโทเค็นเพื่อการเข้าถึงที่ใช้สำหรับการ ให้สิทธิ์
หากต้องการดูการเปลี่ยนแปลงเหล่านี้ โปรดดูข้อมูลเข้าสู่ระบบตัวอย่าง
ขั้นตอนการให้สิทธิ์โดยนัย
แยกการตรวจสอบสิทธิ์และการให้สิทธิ์ของผู้ใช้โดยนำการจัดการโปรไฟล์ผู้ใช้ออกจากโฟลว์การให้สิทธิ์
นำการอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In เหล่านี้ออก
เมธอด
- GoogleUser.getBasicProfile()
- GoogleUser.getId()
ขั้นตอนรหัสการให้สิทธิ์
บริการข้อมูลประจำตัวจะแยกข้อมูลเข้าสู่ระบบในเบราว์เซอร์ออกเป็นโทเค็นรหัสและโทเค็นเพื่อการเข้าถึง การเปลี่ยนแปลงนี้ไม่มีผลกับข้อมูลเข้าสู่ระบบที่ได้รับผ่านการเรียกโดยตรงไปยัง ปลายทาง Google OAuth 2.0 จากแพลตฟอร์มแบ็กเอนด์ หรือผ่านไลบรารีที่ทำงานบนเซิร์ฟเวอร์ที่ปลอดภัยในแพลตฟอร์ม เช่น Google APIs Node.js Client
สถานะเซสชัน
ก่อนหน้านี้ การลงชื่อเข้าใช้ด้วย Google ช่วยให้คุณจัดการสถานะการลงชื่อเข้าใช้ของผู้ใช้ได้โดยใช้สิ่งต่อไปนี้
- ตัวแฮนเดิลการเรียกกลับสำหรับการตรวจสอบสถานะเซสชันของผู้ใช้
- 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.ClientConfig
- gapi.auth2.OfflineAccessOptions
วิธีการ
- gapi.auth2.getAuthInstance()
- GoogleUser.grant()
ขั้นตอนการให้สิทธิ์โดยนัย
เพิ่มTokenClientConfigออบเจ็กต์และinitTokenClient()เรียกใช้
เพื่อกำหนดค่าเว็บแอปตามตัวอย่างในเริ่มต้นไคลเอ็นต์
โทเค็น
แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services:
ออบเจ็กต์
- จำนวนเงิน gapi.auth2.AuthorizeConfigด้วยบัตรTokenClientConfig
วิธีการ
- จำนวนเงิน gapi.auth2.init()ด้วยบัตรgoogle.accounts.oauth2.initTokenClient()
พารามิเตอร์ ได้แก่
- gapi.auth2.AuthorizeConfig.login_hintด้วย- TokenClientConfig.login_hint
- gapi.auth2.GoogleUser.getHostedDomain()ด้วย- TokenClientConfig.hd
ขั้นตอนรหัสการให้สิทธิ์
เพิ่มออบเจ็กต์ CodeClientConfig และเรียกใช้ initCodeClient() เพื่อกำหนดค่า
เว็บแอปตามตัวอย่างในเริ่มต้นไคลเอ็นต์โค้ด
เมื่อเปลี่ยนจากขั้นตอนโดยนัยเป็นขั้นตอนรหัสการให้สิทธิ์ ให้ทำดังนี้
นำ การอ้างอิงไคลเอ็นต์ JavaScript ของการลงชื่อเข้าใช้ด้วย Google ออก
ออบเจ็กต์
- gapi.auth2.AuthorizeConfig
วิธีการ
- gapi.auth2.init()
พารามิเตอร์ ได้แก่
- gapi.auth2.AuthorizeConfig.login_hint
- gapi.auth2.GoogleUser.getHostedDomain()
คำขอโทเค็น
ท่าทางของผู้ใช้ เช่น การคลิกปุ่ม จะสร้างคำขอที่ส่งผลให้มีการส่งคืนโทเค็นเพื่อการเข้าถึงไปยังเบราว์เซอร์ของผู้ใช้โดยตรงด้วยโฟลว์โดยนัย หรือไปยังแพลตฟอร์มแบ็กเอนด์ของคุณหลังจากแลกรหัสการให้สิทธิ์ต่อผู้ใช้เป็นโทเค็นเพื่อการเข้าถึงและโทเค็นเพื่อการรีเฟรช
ขั้นตอนการให้สิทธิ์โดยนัย
คุณอาจขอและใช้โทเค็นการเข้าถึงในเบราว์เซอร์ได้ขณะที่ผู้ใช้ ลงชื่อเข้าใช้และมีเซสชันที่ใช้งานอยู่กับ Google สำหรับโหมดโดยนัย จะต้องมีท่าทางสัมผัสของผู้ใช้ เพื่อขอโทเค็นการเข้าถึง แม้ว่าจะมีการขอมาก่อนแล้วก็ตาม
แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services
วิธีการ
- จำนวนเงิน gapi.auth2.authorize()ด้วยบัตรTokenClient.requestAccessToken()
- GoogleUser.reloadAuthResponse()ที่มี- TokenClient.requestAccessToken()
เพิ่มลิงก์หรือปุ่มเพื่อเรียกใช้ requestAccessToken() เพื่อเริ่ม
โฟลว์ UX แบบป๊อปอัปเพื่อขอโทเค็นเพื่อการเข้าถึง หรือเพื่อรับโทเค็นใหม่เมื่อ
โทเค็นที่มีอยู่หมดอายุ
อัปเดตโค้ดเบสเป็น
- ทริกเกอร์ขั้นตอนโทเค็น OAuth 2.0 ด้วย requestAccessToken()
- รองรับการให้สิทธิ์แบบเพิ่มทีละรายการโดยใช้ requestAccessTokenและOverridableTokenClientConfigเพื่อแยกคำขอเดียวสำหรับขอบเขตหลายรายการ ออกเป็นคำขอที่เล็กลงหลายรายการ
- ขอโทเค็นใหม่เมื่อโทเค็นที่มีอยู่หมดอายุหรือถูกเพิกถอน
การทำงานกับขอบเขตหลายรายการอาจต้องมีการเปลี่ยนแปลงโครงสร้างในโค้ดเบส เพื่อขอสิทธิ์เข้าถึงขอบเขตเฉพาะเมื่อจำเป็นเท่านั้น แทนที่จะขอทั้งหมดในครั้งเดียว ซึ่งเรียกว่าการให้สิทธิ์แบบเพิ่มทีละรายการ คำขอแต่ละรายการควรมีขอบเขตน้อยที่สุดเท่าที่จะเป็นไปได้ และควรมีขอบเขตเดียว ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีอัปเดตแอปเพื่อการให้สิทธิ์แบบค่อยเป็นค่อยไปได้ที่วิธีจัดการความยินยอมของผู้ใช้
เมื่อโทเค็นเพื่อการเข้าถึงหมดอายุ gapi.auth2โมดูลจะรับโทเค็นเพื่อการเข้าถึงใหม่ที่ใช้งานได้สำหรับเว็บแอปของคุณโดยอัตโนมัติ
เพื่อปรับปรุงความปลอดภัยของผู้ใช้ ไลบรารีบริการระบุตัวตนของ Google ไม่รองรับกระบวนการรีเฟรชโทเค็นอัตโนมัตินี้
 คุณต้องอัปเดตเว็บแอปเพื่อตรวจหาโทเค็นเพื่อการเข้าถึงที่หมดอายุและขอโทเค็นใหม่ ดูข้อมูลเพิ่มเติมได้ที่ส่วนการจัดการโทเค็น
ขั้นตอนรหัสการให้สิทธิ์
เพิ่มลิงก์หรือปุ่มเพื่อเรียกใช้ requestCode() เพื่อขอรหัสการให้สิทธิ์
จาก Google ดูตัวอย่างได้ที่ทริกเกอร์ขั้นตอนรหัส OAuth 2.0
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีตอบสนองต่อโทเค็นเพื่อการเข้าถึงที่หมดอายุหรือถูกเพิกถอนได้ที่ส่วนการจัดการโทเค็น
การจัดการโทเค็น
เพิ่มการจัดการข้อผิดพลาดเพื่อตรวจหาการเรียก Google API ที่ล้มเหลวเมื่อใช้โทเค็นเพื่อการเข้าถึงที่หมดอายุหรือ ถูกเพิกถอน และเพื่อขอโทเค็นเพื่อการเข้าถึงใหม่ที่ถูกต้อง
Google APIs จะแสดงรหัสสถานะ HTTP 401 Unauthorized และข้อความแสดงข้อผิดพลาด invalid_token เมื่อมีการใช้โทเค็นการเข้าถึงที่หมดอายุหรือถูกเพิกถอน ดูตัวอย่างได้ที่การตอบกลับโทเค็นไม่ถูกต้อง
โทเค็นที่หมดอายุ
โทเค็นเพื่อการเข้าถึงมีอายุสั้นและมักจะใช้ได้เพียงไม่กี่นาที
การเพิกถอนโทเค็น
เจ้าของบัญชี Google สามารถเพิกถอนความยินยอมที่ให้ไว้ก่อนหน้านี้ได้ทุกเมื่อ การดำเนินการนี้จะทำให้โทเค็นเพื่อการเข้าถึงและโทเค็นการรีเฟรชที่มีอยู่ไม่ถูกต้อง การเพิกถอนอาจเกิดขึ้นจากแพลตฟอร์มของคุณโดยใช้ revoke() หรือผ่านบัญชี
Google
แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services
วิธีการ
- จำนวนเงิน getAuthInstance().disconnect()ด้วยบัตรgoogle.accounts.oauth2.revoke()
- จำนวนเงิน GoogleUser.disconnect()ด้วยบัตรgoogle.accounts.oauth2.revoke()
เรียกใช้ revoke เมื่อผู้ใช้ลบบัญชีในแพลตฟอร์มของคุณ หรือ
ต้องการเพิกถอนความยินยอมในการแชร์ข้อมูลกับแอปของคุณ
ข้อความแจ้งความยินยอมของผู้ใช้
Google จะแสดงกล่องโต้ตอบความยินยอมต่อผู้ใช้เมื่อเว็บแอปหรือแพลตฟอร์มแบ็กเอนด์ ของคุณขอโทเค็นเพื่อการเข้าถึง ดูตัวอย่างกล่องโต้ตอบความยินยอมที่ Google แสดงต่อผู้ใช้
ก่อนที่จะออกโทเค็นเพื่อการเข้าถึงให้กับแอปของคุณ คุณต้องมีเซสชัน Google ที่ใช้งานอยู่เพื่อแจ้งให้ขอความยินยอมจากผู้ใช้และบันทึกผลลัพธ์ ระบบอาจกำหนดให้ผู้ใช้ลงชื่อเข้าใช้บัญชี Google หากยังไม่ได้สร้างเซสชันที่มีอยู่
การลงชื่อเข้าใช้ของผู้ใช้
ผู้ใช้อาจลงชื่อเข้าใช้บัญชี Google ในแท็บเบราว์เซอร์แยกต่างหาก หรือโดยตรงผ่านเบราว์เซอร์หรือระบบปฏิบัติการ เราขอแนะนําให้เพิ่มลงชื่อเข้าใช้ด้วย Google ลงในเว็บไซต์เพื่อสร้างเซสชันที่ใช้งานอยู่ระหว่างบัญชี Google กับเบราว์เซอร์เมื่อผู้ใช้เปิดแอปเป็นครั้งแรก การทําเช่นนี้จะมอบประโยชน์ต่อไปนี้
- ลดจำนวนครั้งที่ผู้ใช้ต้องลงชื่อเข้าใช้ โดยการขอโทเค็นการเข้าถึงจะเริ่มกระบวนการลงชื่อเข้าใช้บัญชี Google หากไม่มีเซสชันที่ใช้งานอยู่
- ใช้ฟิลด์ credential emailของโทเค็นรหัส JWT โดยตรงเป็นค่าของ พารามิเตอร์login_hintในออบเจ็กต์CodeClientConfigหรือTokenClientConfigซึ่งจะเป็นประโยชน์อย่างยิ่งหากแพลตฟอร์มของคุณไม่มี ระบบการจัดการบัญชีผู้ใช้
- ค้นหาและเชื่อมโยงบัญชี Google กับบัญชีผู้ใช้ในเครื่องที่มีอยู่บนแพลตฟอร์มของคุณ เพื่อช่วยลดบัญชีที่ซ้ำกันบนแพลตฟอร์ม
- เมื่อสร้างบัญชีใหม่ในเครื่อง ไดอะล็อกและขั้นตอนการลงชื่อสมัครใช้จะแยกออกจากไดอะล็อกและขั้นตอนการตรวจสอบสิทธิ์ผู้ใช้อย่างชัดเจน ซึ่งจะช่วยลดจำนวนขั้นตอนที่จำเป็นและปรับปรุงอัตราการเลิกกลางคัน
หลังจากลงชื่อเข้าใช้และก่อนที่จะมีการออกโทเค็นเพื่อการเข้าถึง ผู้ใช้ต้องให้ความยินยอม สำหรับแอปพลิเคชันของคุณสำหรับขอบเขตที่ขอ
การตอบกลับของโทเค็นและความยินยอม
หลังจากได้รับความยินยอมแล้ว ระบบจะแสดงโทเค็นเพื่อเข้าถึงพร้อมกับรายการขอบเขตที่ผู้ใช้ อนุมัติหรือปฏิเสธ
สิทธิ์แบบละเอียดช่วยให้ผู้ใช้สามารถอนุมัติหรือปฏิเสธขอบเขตแต่ละรายการได้ เมื่อ ขอสิทธิ์เข้าถึงหลายขอบเขต ระบบจะให้สิทธิ์หรือปฏิเสธแต่ละขอบเขต โดยไม่ขึ้นอยู่กับขอบเขตอื่นๆ แอปของคุณจะเปิดใช้ฟีเจอร์และฟังก์ชันการทำงานที่ขึ้นอยู่กับขอบเขตแต่ละรายการโดยเลือกตามที่ผู้ใช้เลือก
ขั้นตอนการให้สิทธิ์โดยนัย
แทนที่ การอ้างอิงไคลเอ็นต์ JavaScript ของ Google Sign-In ด้วย Google Identity Services:
ออบเจ็กต์
- จำนวนเงิน gapi.auth2.AuthorizeResponseด้วยบัตรTokenClient.TokenResponse
- จำนวนเงิน gapi.auth2.AuthResponseด้วยบัตรTokenClient.TokenResponse
วิธีการ
- GoogleUser.hasGrantedScopes()ที่มี- google.accounts.oauth2.hasGrantedAllScopes()
- GoogleUser.getGrantedScopes()ที่มี- google.accounts.oauth2.hasGrantedAllScopes()
นำ การอ้างอิงไคลเอ็นต์ JavaScript ของการลงชื่อเข้าใช้ด้วย Google ออกโดยทำดังนี้
วิธีการ
- GoogleUser.getAuthResponse()
อัปเดตเว็บแอปด้วย hasGrantedAllScopes() และ
hasGrantedAnyScope() โดยทำตามตัวอย่างสิทธิ์แบบละเอียดนี้
ขั้นตอนรหัสการให้สิทธิ์
อัปเดตหรือเพิ่มปลายทางรหัสการให้สิทธิ์ลงในแพลตฟอร์มแบ็กเอนด์ โดยทำตามวิธีการในการจัดการรหัสการให้สิทธิ์
อัปเดตแพลตฟอร์มให้ทำตามขั้นตอนที่อธิบายไว้ในคู่มือใช้โมเดลโค้ด เพื่อตรวจสอบคำขอและรับโทเค็นเพื่อการเข้าถึงและโทเค็น การรีเฟรช
อัปเดตแพลตฟอร์มเพื่อเปิดหรือปิดใช้ฟีเจอร์และ ฟังก์ชันการทำงานบางอย่างตามขอบเขตแต่ละรายการที่ผู้ใช้ได้อนุมัติโดย ทำตามวิธีการสำหรับการให้สิทธิ์แบบเพิ่มทีละรายการ และตรวจสอบ ขอบเขตการเข้าถึงที่ผู้ใช้ให้สิทธิ์
ตัวอย่างขั้นตอนการให้สิทธิ์โดยนัย
วิธีเดิม
ไลบรารีของไคลเอ็นต์ GAPI
ตัวอย่างไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript ที่ทำงานในเบราว์เซอร์โดยใช้กล่องโต้ตอบแบบป๊อปอัปเพื่อขอความยินยอมจากผู้ใช้
gapi.auth2 โมดูลจะโหลดและใช้โดย
gapi.client.init()โดยอัตโนมัติ จึงซ่อนอยู่
<!DOCTYPE html>
  <html>
    <head>
      <script src="https://apis.google.com/js/api.js"></script>
      <script>
        function start() {
          gapi.client.init({
            'apiKey': 'YOUR_API_KEY',
            'clientId': 'YOUR_CLIENT_ID',
            'scope': 'https://www.googleapis.com/auth/cloud-translation',
            'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
          }).then(function() {
            // Execute an API request which is returned as a Promise.
            // The method name language.translations.list comes from the API discovery.
            return gapi.client.language.translations.list({
              q: 'hello world',
              source: 'en',
              target: 'de',
            });
          }).then(function(response) {
            console.log(response.result.data.translations[0].translatedText);
          }, function(reason) {
            console.log('Error: ' + reason.result.error.message);
          });
        };
        // Load the JavaScript client library and invoke start afterwards.
        gapi.load('client', start);
      </script>
    </head>
    <body>
      <div id="results"></div>
    </body>
  </html>
ไลบรารีของไคลเอ็นต์ JS
OAuth 2.0 สำหรับเว็บแอปพลิเคชันฝั่งไคลเอ็นต์ที่ทํางานในเบราว์เซอร์โดยใช้ กล่องโต้ตอบป๊อปอัปเพื่อขอความยินยอมจากผู้ใช้
โหลดโมดูล gapi.auth2 ด้วยตนเอง
<!DOCTYPE html>
<html><head></head><body>
<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }
  function initClient() {
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';
    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from Google Cloud console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'clientId': 'YOUR_CLIENT_ID',
        'discoveryDocs': [discoveryUrl],
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();
      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);
      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();
      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      });
      $('#revoke-access-button').click(function() {
        revokeAccess();
      });
    });
  }
  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked "Sign out" button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }
  function revokeAccess() {
    GoogleAuth.disconnect();
  }
  function setSigninStatus() {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');
    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }
  function updateSigninStatus() {
    setSigninStatus();
  }
</script>
<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>
<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
        onload="this.onload=function(){};handleClientLoad()"
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body></html>
ปลายทาง OAuth 2.0
OAuth 2.0 สำหรับเว็บแอปพลิเคชันฝั่งไคลเอ็นต์ที่ทำงานในเบราว์เซอร์โดยใช้ การเปลี่ยนเส้นทางไปยัง Google เพื่อขอความยินยอมจากผู้ใช้
ตัวอย่างนี้แสดงการเรียกปลายทาง OAuth 2.0 ของ Google โดยตรงจากเบราว์เซอร์ของผู้ใช้ และไม่ได้ใช้โมดูล gapi.auth2 หรือไลบรารี JavaScript
<!DOCTYPE html>
<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
  var fragmentString = location.hash.substring(1);
  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0) {
    localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
    if (params['state'] && params['state'] == 'try_sample_request') {
      trySampleRequest();
    }
  }
  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          'access_token=' + params['access_token']);
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.response);
        } else if (xhr.readyState === 4 && xhr.status === 401) {
          // Token invalid, so prompt for user permission.
          oauth2SignIn();
        }
      };
      xhr.send(null);
    } else {
      oauth2SignIn();
    }
  }
  /*
    *   Create form to request access token from Google's OAuth 2.0 server.
 */
function oauth2SignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);
    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                  'state': 'try_sample_request',
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};
    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }
    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>
<button onclick="trySampleRequest();">Try sample request</button>
</body></html>
วิธีใหม่
GIS เท่านั้น
ตัวอย่างนี้แสดงเฉพาะไลบรารี JavaScript ของบริการระบุตัวตนของ Google ที่ใช้รูปแบบโทเค็นและกล่องโต้ตอบป๊อปอัปสำหรับความยินยอมของผู้ใช้ โดยมีไว้เพื่อแสดงจำนวนขั้นตอนขั้นต่ำที่ต้องใช้ในการกำหนดค่าไคลเอ็นต์ ส่งคำขอและรับโทเค็นการเข้าถึง รวมถึงเรียกใช้ Google API
<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      var access_token;
      function initClient() {
        client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/contacts.readonly',
          callback: (tokenResponse) => {
            access_token = tokenResponse.access_token;
          },
        });
      }
      function getToken() {
        client.requestAccessToken();
      }
      function revokeToken() {
        google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
      }
      function loadCalendar() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
        xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
        xhr.send();
      }
    </script>
    <h1>Google Identity Services Authorization Token model</h1>
    <button onclick="getToken();">Get access token</button><br><br>
    <button onclick="loadCalendar();">Load Calendar</button><br><br>
    <button onclick="revokeToken();">Revoke token</button>
  </body>
</html>
async/await ของ GAPI
ตัวอย่างนี้แสดงวิธีเพิ่มไลบรารีบริการข้อมูลประจำตัวของ Google โดยใช้
รูปแบบโทเค็น นำโมดูล gapi.auth2 ออก และเรียกใช้ API โดยใช้ไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript
ใช้ Promise, async และ await เพื่อบังคับลำดับการโหลดไลบรารี รวมถึงเพื่อ ตรวจหาและลองอีกครั้งสำหรับข้อผิดพลาดในการให้สิทธิ์ ระบบจะเรียก API หลังจากที่โทเค็นเพื่อการเข้าถึงที่ถูกต้องพร้อมใช้งานแล้วเท่านั้น
ผู้ใช้ควรจะกดปุ่ม "แสดงปฏิทิน" เมื่อไม่มีโทเค็นเพื่อการเข้าถึง เมื่อโหลดหน้าเว็บเป็นครั้งแรก หรือหลังจากโทเค็นเพื่อการเข้าถึง หมดอายุแล้ว
<!DOCTYPE html>
<html>
<head>
    <title>GAPI and GIS Example</title>
    <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
    <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoad()"></script>
</head>
<body>
    <h1>GAPI Client with GIS Authorization</h1>
    <button id="authorizeBtn" style="visibility:hidden;">Authorize and Load Events</button>
    <button id="revokeBtn" style="visibility:hidden;">Revoke Access</button>
    <div id="content"></div>
    <script>
        const YOUR_CLIENT_ID = "YOUR_CLIENT_ID";
        const YOUR_API_KEY = 'YOUR_API_KEY';
        const CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly';
        let tokenClient;
        let libsLoaded = 0;
        function gapiLoad() {
            gapi.load('client', initGapiClient);
        }
        async function initGapiClient() {
            try {
                await gapi.client.init({ apiKey: YOUR_API_KEY });
                await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
                console.log('GAPI client initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GAPI initialization failed:', err);
            }
        }
        function gisLoad() {
            try {
                tokenClient = google.accounts.oauth2.initTokenClient({
                    client_id: YOUR_CLIENT_ID,
                    scope: CALENDAR_SCOPE,
                    callback: '', // Will be set dynamically
                    error_callback: handleGisError,
                });
                console.log('GIS TokenClient initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GIS initialization failed:', err);
            }
        }
        function checkAllLoaded() {
            libsLoaded++;
            if (libsLoaded === 2) {
                document.getElementById('authorizeBtn').style.visibility = 'visible';
                document.getElementById('revokeBtn').style.visibility = 'visible';
                document.getElementById('authorizeBtn').onclick = makeApiCall;
                document.getElementById('revokeBtn').onclick = revokeAccess;
                console.log('Ready to authorize.');
            }
        }
        function handleGisError(err) {
            console.error('GIS Error:', err);
            let message = 'An error occurred during authorization.';
            if (err && err.type === 'popup_failed_to_open') {
                message = 'Failed to open popup. Please disable popup blockers.';
            } else if (err && err.type === 'popup_closed') {
                message = 'Authorization popup was closed.';
            }
            document.getElementById('content').textContent = message;
        }
        function handleError(message, error) {
            console.error(message, error);
            document.getElementById('content').textContent = `${message} ${error.message || JSON.stringify(error)}`;
        }
        async function makeApiCall() {
            document.getElementById('content').textContent = 'Processing...';
            try {
                let token = gapi.client.getToken();
                if (!token || !token.access_token) {
                    console.log('No token, fetching one...');
                    await getToken();
                }
                console.log('Calling Calendar API...');
                const response = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                displayEvents(response.result);
            } catch (err) {
                console.error('API call failed:', err);
                const errorInfo = err.result && err.result.error;
                if (errorInfo && (errorInfo.code === 401 || (errorInfo.code === 403 && errorInfo.status === "PERMISSION_DENIED"))) {
                    console.log('Auth error on API call, refreshing token...');
                    try {
                        await getToken({ prompt: 'consent' }); // Force refresh
                        const retryResponse = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                        displayEvents(retryResponse.result);
                    } catch (refreshErr) {
                        handleError('Failed to refresh token or retry API call:', refreshErr);
                    }
                } else {
                    handleError('Error loading events:', err.result ? err.result.error : err);
                }
            }
        }
        async function getToken(options = { prompt: '' }) {
            return new Promise((resolve, reject) => {
                if (!tokenClient) return reject(new Error("GIS TokenClient not initialized."));
                tokenClient.callback = (tokenResponse) => {
                    if (tokenResponse.error) {
                        reject(new Error(`Token Error: ${tokenResponse.error} - ${tokenResponse.error_description}`));
                    } else {
                        console.log('Token acquired.');
                        resolve(tokenResponse);
                    }
                };
                tokenClient.requestAccessToken(options);
            });
        }
        function displayEvents(result) {
            const events = result.items;
            if (events && events.length > 0) {
                let eventList = '<h3>Upcoming Events:</h3><ul>' + events.map(event =>
                    `<li>${event.summary} (${event.start.dateTime || event.start.date})</li>`
                ).join('') + '</ul>';
                document.getElementById('content').innerHTML = eventList;
            } else {
                document.getElementById('content').textContent = 'No upcoming events found.';
            }
        }
        function revokeAccess() {
            const token = gapi.client.getToken();
            if (token && token.access_token) {
                google.accounts.oauth2.revoke(token.access_token, () => {
                    console.log('Access revoked.');
                    document.getElementById('content').textContent = 'Access has been revoked.';
                    gapi.client.setToken(null);
                });
            } else {
                document.getElementById('content').textContent = 'No token to revoke.';
            }
        }
    </script>
</body>
</html>
การเรียกกลับของ GAPI
ตัวอย่างนี้แสดงวิธีเพิ่มไลบรารีบริการข้อมูลประจำตัวของ Google โดยใช้
รูปแบบโทเค็น นำโมดูล gapi.auth2 ออก และเรียกใช้ API โดยใช้ไลบรารีของไคลเอ็นต์ Google API สำหรับ JavaScript
ตัวแปรใช้เพื่อบังคับลำดับการโหลดไลบรารี การเรียกใช้ GAPI จะดำเนินการ จากภายในฟังก์ชันเรียกกลับหลังจากที่ระบบส่งคืนโทเค็นเพื่อการเข้าถึงที่ถูกต้อง
ผู้ใช้ควรจะกดปุ่ม "แสดงปฏิทิน" เมื่อหน้าเว็บโหลดเป็นครั้งแรก และอีกครั้งเมื่อต้องการรีเฟรชข้อมูลปฏิทิน
<!DOCTYPE html>
<html>
<head>
  <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
</head>
<body>
  <h1>GAPI with GIS callbacks</h1>
  <button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
  <button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>
  <script>
    let tokenClient;
    let gapiInited;
    let gisInited;
    document.getElementById("showEventsBtn").style.visibility="hidden";
    document.getElementById("revokeBtn").style.visibility="hidden";
    function checkBeforeStart() {
       if (gapiInited && gisInited){
          // Start only when both gapi and gis are initialized.
          document.getElementById("showEventsBtn").style.visibility="visible";
          document.getElementById("revokeBtn").style.visibility="visible";
       }
    }
    function gapiInit() {
      gapi.client.init({
        // NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
      })
      .then(function() {  // Load the Calendar API discovery document.
        gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
        gapiInited = true;
        checkBeforeStart();
      });
    }
    function gapiLoad() {
        gapi.load('client', gapiInit)
    }
    function gisInit() {
     tokenClient = google.accounts.oauth2.initTokenClient({
                client_id: 'YOUR_CLIENT_ID',
                scope: 'https://www.googleapis.com/auth/calendar.readonly',
                callback: '',  // defined at request time
            });
      gisInited = true;
      checkBeforeStart();
    }
    function showEvents() {
      tokenClient.callback = (resp) => {
        if (resp.error !== undefined) {
          throw(resp);
        }
        // GIS has automatically updated gapi.client with the newly issued access token.
        console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));
        gapi.client.calendar.events.list({ 'calendarId': 'primary' })
        .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
        .catch(err => console.log(err));
        document.getElementById("showEventsBtn").innerText = "Refresh Calendar";
      }
      // Conditionally ask users to select the Google Account they'd like to use,
      // and explicitly obtain their consent to fetch their Calendar.
      // NOTE: To request an access token a user gesture is necessary.
      if (gapi.client.getToken() === null) {
        // Prompt the user to select a Google Account and asked for consent to share their data
        // when establishing a new session.
        tokenClient.requestAccessToken({prompt: 'consent'});
      } else {
        // Skip display of account chooser and consent dialog for an existing session.
        tokenClient.requestAccessToken({prompt: ''});
      }
    }
    function revokeToken() {
      let cred = gapi.client.getToken();
      if (cred !== null) {
        google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
        gapi.client.setToken('');
        document.getElementById("showEventsBtn").innerText = "Show Calendar";
      }
    }
  </script>
</body>
</html>
ตัวอย่างขั้นตอนรหัสการให้สิทธิ์
UX ป๊อปอัปของไลบรารี Google Identity Service สามารถใช้การเปลี่ยนเส้นทาง URL เพื่อ ส่งคืนรหัสการให้สิทธิ์ไปยังปลายทางโทเค็นแบ็กเอนด์โดยตรง หรือใช้ ตัวแฮนเดิลการเรียกกลับ JavaScript ที่ทำงานในเบราว์เซอร์ของผู้ใช้ซึ่งทำหน้าที่เป็นพร็อกซี การตอบกลับไปยังแพลตฟอร์มของคุณ ไม่ว่าจะในกรณีใด แพลตฟอร์มแบ็กเอนด์จะทำโฟลว์ OAuth 2.0 ให้เสร็จสมบูรณ์เพื่อรับโทเค็นการรีเฟรชและโทเค็นเพื่อการเข้าถึงที่ถูกต้อง
วิธีเดิม
เว็บแอปฝั่งเซิร์ฟเวอร์
Google Sign-In สำหรับแอปฝั่งเซิร์ฟเวอร์ที่ทำงานในแพลตฟอร์มแบ็กเอนด์ โดยใช้การเปลี่ยนเส้นทางไปยัง Google เพื่อขอความยินยอมจากผู้ใช้
<!DOCTYPE html>
<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
    <script>
      function start() {
        gapi.load('auth2', function() {
          auth2 = gapi.auth2.init({
            client_id: 'YOUR_CLIENT_ID',
            api_key: 'YOUR_API_KEY',
            discovery_docs: ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
            // Scopes to request in addition to 'profile' and 'email'
            scope: 'https://www.googleapis.com/auth/cloud-translation',
          });
        });
      }
      function signInCallback(authResult) {
        if (authResult['code']) {
          console.log("sending AJAX request");
          // Send authorization code obtained from Google to backend platform
          $.ajax({
            type: 'POST',
            url: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
            // Always include an X-Requested-With header to protect against CSRF attacks.
            headers: {
              'X-Requested-With': 'XMLHttpRequest'
            },
            contentType: 'application/octet-stream; charset=utf-8',
            success: function(result) {
              console.log(result);
            },
            processData: false,
            data: authResult['code']
          });
        } else {
          console.log('error: failed to obtain authorization code')
        }
      }
    </script>
  </head>
  <body>
    <button id="signinButton">Sign In With Google</button>
    <script>
      $('#signinButton').click(function() {
        // Obtain an authorization code from Google
        auth2.grantOfflineAccess().then(signInCallback);
      });
    </script>
  </body>
</html>
HTTP/REST โดยใช้การเปลี่ยนเส้นทาง
การใช้ OAuth 2.0 สำหรับแอปพลิเคชันเว็บเซิร์ฟเวอร์เพื่อส่งรหัสการให้สิทธิ์ จากเบราว์เซอร์ของผู้ใช้ไปยังแพลตฟอร์มแบ็กเอนด์ ความยินยอมของผู้ใช้ที่จัดการโดย เปลี่ยนเส้นทางเบราว์เซอร์ของผู้ใช้ไปยัง Google
/\*
 \* Create form to request access token from Google's OAuth 2.0 server.
 \*/
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
  // Create <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"
    }
  }