เอกสารนี้อธิบายวิธีที่แอปพลิเคชันเว็บเซิร์ฟเวอร์ใช้ไลบรารีของไคลเอ็นต์ Google API หรือปลายทาง Google OAuth 2.0 เพื่อใช้การให้สิทธิ์ OAuth 2.0 ในการเข้าถึง Google API
OAuth 2.0 อนุญาตให้ผู้ใช้แชร์ข้อมูลบางอย่างกับแอปพลิเคชันโดยที่ยังเก็บชื่อผู้ใช้ รหัสผ่าน และข้อมูลอื่นๆ ไว้เป็นส่วนตัว ตัวอย่างเช่น แอปพลิเคชันสามารถใช้ OAuth 2.0 เพื่อขอสิทธิ์จากผู้ใช้ในการจัดเก็บไฟล์ใน Google ไดรฟ์
ขั้นตอน OAuth 2.0 นี้มีไว้สำหรับการให้สิทธิ์ผู้ใช้โดยเฉพาะ ซึ่งออกแบบมาสำหรับแอปพลิเคชันที่สามารถจัดเก็บข้อมูลลับและรักษาสถานะได้ แอปพลิเคชันเว็บเซิร์ฟเวอร์ที่ได้รับสิทธิ์อย่างถูกต้องจะเข้าถึง API ได้ขณะที่ผู้ใช้โต้ตอบกับแอปพลิเคชันหรือหลังจากที่ผู้ใช้ออกจากแอปพลิเคชันแล้ว
แอปพลิเคชันเว็บเซิร์ฟเวอร์มักจะใช้ บัญชีบริการเพื่อให้สิทธิ์คำขอ API ด้วย โดยเฉพาะเมื่อเรียกใช้ Cloud API เพื่อเข้าถึงข้อมูลตามโปรเจ็กต์แทนข้อมูลเฉพาะผู้ใช้ แอปพลิเคชันเว็บเซิร์ฟเวอร์สามารถใช้บัญชีบริการร่วมกับการให้สิทธิ์ของผู้ใช้
ไลบรารีของไคลเอ็นต์
ตัวอย่างเฉพาะภาษาในหน้านี้ใช้ไลบรารีของไคลเอ็นต์ Google API เพื่อใช้การให้สิทธิ์ OAuth 2.0 หากต้องการเรียกใช้ตัวอย่างโค้ด คุณต้องติดตั้งไลบรารีของไคลเอ็นต์สำหรับภาษาของคุณก่อน
เมื่อคุณใช้ไลบรารีของไคลเอ็นต์ Google API เพื่อจัดการขั้นตอน OAuth 2.0 ของแอปพลิเคชัน ไลบรารีของไคลเอ็นต์จะดำเนินการหลายอย่างที่แอปพลิเคชันจะต้องจัดการเอง เช่น กำหนดเวลาที่แอปพลิเคชันสามารถใช้หรือรีเฟรชโทเค็นเพื่อการเข้าถึงที่จัดเก็บไว้ รวมถึงเวลาที่แอปพลิเคชันต้องขอความยินยอมอีกครั้ง นอกจากนี้ ไลบรารีของไคลเอ็นต์ยังสร้าง URL เปลี่ยนเส้นทางที่ถูกต้องและช่วยใช้เครื่องมือจัดการการเปลี่ยนเส้นทางที่แลกเปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นเพื่อการเข้าถึง
ไลบรารีของไคลเอ็นต์ Google API สำหรับแอปพลิเคชันฝั่งเซิร์ฟเวอร์พร้อมใช้งานในภาษาต่อไปนี้
ข้อกำหนดเบื้องต้น
เปิดใช้ API สำหรับโปรเจ็กต์
แอปพลิเคชันที่เรียกใช้ Google API จะต้องเปิดใช้ API เหล่านั้นในคอนโซล API
วิธีเปิดใช้ API สำหรับโปรเจ็กต์
- เปิดคลัง API ในคอนโซล Google API
- หากได้รับข้อความแจ้ง ให้เลือกโปรเจ็กต์หรือสร้างโปรเจ็กต์ใหม่
- ไลบรารี API จะแสดง API ทั้งหมดที่มีอยู่ โดยจัดกลุ่มตามตระกูลผลิตภัณฑ์และความนิยม หาก API ที่ต้องการเปิดใช้ไม่ปรากฏในรายการ ให้ใช้การค้นหาเพื่อค้นหา API หรือคลิกดูทั้งหมดในกลุ่มผลิตภัณฑ์ที่ API นั้นอยู่
- เลือก API ที่ต้องการเปิดใช้ แล้วคลิกปุ่มเปิดใช้
- เปิดใช้การเรียกเก็บเงินเมื่อได้รับข้อความแจ้ง
- หากได้รับข้อความแจ้ง ให้อ่านและยอมรับข้อกำหนดในการให้บริการของ API
สร้างข้อมูลเข้าสู่ระบบสำหรับการให้สิทธิ์
แอปพลิเคชันที่ใช้ OAuth 2.0 เพื่อเข้าถึง Google APIs ต้องมีข้อมูลเข้าสู่ระบบการให้สิทธิ์ที่ระบุแอปพลิเคชันไปยังเซิร์ฟเวอร์ OAuth 2.0 ของ Google ขั้นตอนต่อไปนี้จะอธิบายวิธีสร้างข้อมูลเข้าสู่ระบบสำหรับโปรเจ็กต์ จากนั้นแอปพลิเคชันจะใช้ข้อมูลเข้าสู่ระบบเพื่อเข้าถึง API ที่คุณเปิดใช้สำหรับโปรเจ็กต์นั้นได้
- ไปที่หน้าลูกค้า
- คลิกสร้างไคลเอ็นต์
- เลือกประเภทแอปพลิเคชันเป็นเว็บแอปพลิเคชัน
- กรอกแบบฟอร์ม แล้วคลิกสร้าง แอปพลิเคชันที่ใช้ภาษาและเฟรมเวิร์ก เช่น PHP, Java, Python, Ruby และ .NET ต้องระบุ URI เปลี่ยนเส้นทางที่ได้รับอนุญาต URI เปลี่ยนเส้นทางคือปลายทางที่เซิร์ฟเวอร์ OAuth 2.0 สามารถส่งการตอบกลับได้ ปลายทางเหล่านี้ต้องเป็นไปตามกฎการตรวจสอบของ Google
สำหรับการทดสอบ คุณสามารถระบุ URI ที่อ้างอิงถึงเครื่องในเครื่อง เช่น
http://localhost:8080ตัวอย่างทั้งหมดในเอกสารนี้ใช้http://localhost:8080เป็น URI การเปลี่ยนเส้นทางเราขอแนะนำให้คุณออกแบบปลายทางการตรวจสอบสิทธิ์ของแอปเพื่อไม่ให้แอปพลิเคชันแสดงรหัสการให้สิทธิ์แก่แหล่งข้อมูลอื่นๆ ในหน้าเว็บ
หลังจากสร้างข้อมูลเข้าสู่ระบบแล้ว ให้ดาวน์โหลดไฟล์ client_secret.json จากคอนโซล API จัดเก็บไฟล์อย่างปลอดภัยในตำแหน่งที่มีเพียงแอปพลิเคชันของคุณเท่านั้นที่เข้าถึงได้
ระบุขอบเขตการเข้าถึง
ขอบเขตช่วยให้แอปพลิเคชันขอสิทธิ์เข้าถึงเฉพาะทรัพยากรที่จำเป็นเท่านั้น และยังช่วยให้ผู้ใช้ควบคุมปริมาณการเข้าถึงที่ให้แก่แอปพลิเคชันของคุณได้ด้วย ดังนั้น จำนวนขอบเขตที่ขอและความเป็นไปได้ที่จะได้รับความยินยอมจากผู้ใช้อาจมีความสัมพันธ์แบบผกผันกัน
ก่อนเริ่มใช้การให้สิทธิ์ OAuth 2.0 เราขอแนะนำให้คุณระบุขอบเขตที่แอปจะต้องได้รับสิทธิ์เข้าถึง
นอกจากนี้ เราขอแนะนำให้แอปพลิเคชันของคุณขอสิทธิ์เข้าถึงขอบเขตการให้สิทธิ์ผ่านกระบวนการการให้สิทธิ์แบบเพิ่มขึ้น ซึ่งแอปพลิเคชันของคุณจะขอสิทธิ์เข้าถึงข้อมูลผู้ใช้ในบริบท แนวทางปฏิบัติแนะนำนี้ช่วยให้ผู้ใช้เข้าใจได้ง่ายขึ้นว่าเหตุใดแอปพลิเคชันของคุณจึงต้องการสิทธิ์เข้าถึงที่ขอ
เอกสารขอบเขต OAuth 2.0 API มีรายการขอบเขตทั้งหมดที่คุณอาจใช้เพื่อเข้าถึง Google APIs
ข้อกำหนดเฉพาะภาษา
หากต้องการเรียกใช้ตัวอย่างโค้ดในเอกสารนี้ คุณจะต้องมีบัญชี Google, สิทธิ์เข้าถึงอินเทอร์เน็ต และเว็บเบราว์เซอร์ หากคุณใช้ไลบรารีของไคลเอ็นต์ API รายการใดรายการหนึ่ง โปรดดูข้อกำหนดเฉพาะภาษาในส่วนต่อไปนี้ด้วย
PHP
หากต้องการเรียกใช้ตัวอย่างโค้ด PHP ในเอกสารนี้ คุณจะต้องมีสิ่งต่อไปนี้
- PHP 8.0 ขึ้นไปที่มีอินเทอร์เฟซบรรทัดคำสั่ง (CLI) และส่วนขยาย JSON ติดตั้งอยู่
- เครื่องมือการจัดการทรัพยากร Dependency ของ Composer
-
ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ PHP มีดังนี้
composer require google/apiclient:^2.15.0
ดูข้อมูลเพิ่มเติมได้ที่ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ PHP
Python
หากต้องการเรียกใช้ตัวอย่างโค้ด Python ในเอกสารนี้ คุณจะต้องมีสิ่งต่อไปนี้
- Python 3.7 ขึ้นไป
- เครื่องมือการจัดการแพ็กเกจ pip
- ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ Python 2.0 มีการเผยแพร่ดังนี้
pip install --upgrade google-api-python-client
google-auth,google-auth-oauthlibและgoogle-auth-httplib2สำหรับการให้สิทธิ์ผู้ใช้pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
- เฟรมเวิร์กเว็บแอปพลิเคชัน Flask Python
pip install --upgrade flask
- ไลบรารี HTTP
requestspip install --upgrade requests
อ่านบันทึกประจำรุ่นของไลบรารีของไคลเอ็นต์ Python สำหรับ Google API หากคุณอัปเกรด Python และคำแนะนำในการย้ายข้อมูลที่เกี่ยวข้องไม่ได้
Ruby
หากต้องการเรียกใช้ตัวอย่างโค้ด Ruby ในเอกสารนี้ คุณจะต้องมีสิ่งต่อไปนี้
- Ruby 2.6 ขึ้นไป
-
ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Ruby:
gem install googleauth
-
ไลบรารีของไคลเอ็นต์สำหรับ Google APIs ของไดรฟ์และปฏิทินมีดังนี้
gem install google-apis-drive_v3 google-apis-calendar_v3
-
เฟรมเวิร์กเว็บแอปพลิเคชัน Sinatra Ruby
gem install sinatra
Node.js
หากต้องการเรียกใช้ตัวอย่างโค้ด Node.js ในเอกสารนี้ คุณจะต้องมีสิ่งต่อไปนี้
- LTS สำหรับการบำรุงรักษา, LTS ที่ใช้งานอยู่ หรือ Node.js รุ่นปัจจุบัน
-
ไคลเอ็นต์ Node.js ของ Google APIs
npm install googleapis crypto express express-session
HTTP/REST
คุณไม่จำเป็นต้องติดตั้งไลบรารีใดๆ เพื่อให้สามารถเรียกใช้ปลายทาง OAuth 2.0 ได้โดยตรง
การรับโทเค็นเพื่อการเข้าถึง OAuth 2.0
ขั้นตอนต่อไปนี้แสดงวิธีที่แอปพลิเคชันโต้ตอบกับเซิร์ฟเวอร์ OAuth 2.0 ของ Google เพื่อขอความยินยอมจากผู้ใช้ในการส่งคำขอ API ในนามของผู้ใช้ แอปพลิเคชันของคุณต้องได้รับความยินยอมดังกล่าวก่อนจึงจะดำเนินการตามคำขอ Google API ที่ต้องมีการให้สิทธิ์จากผู้ใช้ได้
รายการต่อไปนี้จะสรุปขั้นตอนเหล่านี้อย่างรวดเร็ว
- แอปพลิเคชันจะระบุสิทธิ์ที่ต้องการ
- แอปพลิเคชันจะเปลี่ยนเส้นทางผู้ใช้ไปยัง Google พร้อมกับรายการสิทธิ์ที่ขอ
- ผู้ใช้จะตัดสินใจว่าจะให้สิทธิ์แก่แอปพลิเคชันของคุณหรือไม่
- แอปพลิเคชันจะค้นหาสิ่งที่ผู้ใช้ตัดสินใจ
- หากผู้ใช้ให้สิทธิ์ที่ขอ แอปพลิเคชันจะดึงข้อมูลโทเค็นที่จำเป็นในการส่งคำขอ API ในนามของผู้ใช้
ขั้นตอนที่ 1: ตั้งค่าพารามิเตอร์การให้สิทธิ์
ขั้นตอนแรกคือการสร้างคำขอการให้สิทธิ์ คำขอดังกล่าวจะตั้งค่าพารามิเตอร์ที่ระบุแอปพลิเคชันของคุณและกำหนดสิทธิ์ที่ระบบจะขอให้ผู้ใช้ให้สิทธิ์แก่แอปพลิเคชันของคุณ
- หากใช้ไลบรารีของไคลเอ็นต์ Google สำหรับการตรวจสอบสิทธิ์และการให้สิทธิ์ OAuth 2.0 คุณจะต้องสร้างและกำหนดค่าออบเจ็กต์ที่กำหนดพารามิเตอร์เหล่านี้
- หากเรียกปลายทาง Google OAuth 2.0 โดยตรง คุณจะต้องสร้าง URL และตั้งค่าพารามิเตอร์ใน URL นั้น
แท็บต่อไปนี้จะกำหนดพารามิเตอร์การให้สิทธิ์ที่รองรับสำหรับแอปพลิเคชันเว็บเซิร์ฟเวอร์ ตัวอย่างเฉพาะภาษาโปรแกรมยังแสดงวิธีใช้ไลบรารีของไคลเอ็นต์หรือไลบรารีการให้สิทธิ์เพื่อกำหนดค่าออบเจ็กต์ที่ตั้งค่าพารามิเตอร์เหล่านั้นด้วย
PHP
ข้อมูลโค้ดต่อไปนี้จะสร้างออบเจ็กต์ Google\Client() ซึ่งกำหนดพารามิเตอร์ในคำขอการให้สิทธิ์
ออบเจ็กต์ดังกล่าวจะใช้ข้อมูลจากไฟล์ client_secret.json เพื่อระบุแอปพลิเคชันของคุณ (ดูข้อมูลเพิ่มเติมเกี่ยวกับไฟล์ดังกล่าวได้ที่การสร้างข้อมูลเข้าสู่ระบบเพื่อการให้สิทธิ์) ออบเจ็กต์ยังระบุขอบเขตที่แอปพลิเคชันของคุณขอสิทธิ์เข้าถึงและ URL ไปยังปลายทางการตรวจสอบสิทธิ์ของแอปพลิเคชัน ซึ่งจะจัดการการตอบกลับจากเซิร์ฟเวอร์ OAuth 2.0 ของ Google สุดท้าย โค้ดจะตั้งค่าพารามิเตอร์ access_type และ include_granted_scopes ที่ไม่บังคับ
ตัวอย่างเช่น โค้ดนี้จะขอสิทธิ์เข้าถึงข้อมูลเมตาใน Google ไดรฟ์และกิจกรรมในปฏิทินของผู้ใช้แบบอ่านอย่างเดียวและแบบออฟไลน์
use Google\Client; $client = new Client(); // Required, call the setAuthConfig function to load authorization credentials from // client_secret.json file. $client->setAuthConfig('client_secret.json'); // Required, to set the scope value, call the addScope function $client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]); // Required, call the setRedirectUri function to specify a valid redirect URI for the // provided client_id $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'); // Recommended, offline access will give you both an access and refresh token so that // your app can refresh the access token without user interaction. $client->setAccessType('offline'); // Recommended, call the setState function. Using a state value can increase your assurance that // an incoming connection is the result of an authentication request. $client->setState($sample_passthrough_value); // Optional, if your application knows which user is trying to authenticate, it can use this // parameter to provide a hint to the Google Authentication Server. $client->setLoginHint('hint@example.com'); // Optional, call the setPrompt function to set "consent" will prompt the user for consent $client->setPrompt('consent'); // Optional, call the setIncludeGrantedScopes function with true to enable incremental // authorization $client->setIncludeGrantedScopes(true);
Python
ข้อมูลโค้ดต่อไปนี้ใช้โมดูล google-auth-oauthlib.flow เพื่อสร้างคำขอการให้สิทธิ์
โค้ดจะสร้างออบเจ็กต์ Flow ซึ่งระบุแอปพลิเคชันของคุณโดยใช้ข้อมูลจากไฟล์ client_secret.json ที่คุณดาวน์โหลดหลังจากสร้างข้อมูลเข้าสู่ระบบสำหรับการให้สิทธิ์ ออบเจ็กต์ดังกล่าวยังระบุขอบเขตที่แอปพลิเคชันของคุณขอสิทธิ์เข้าถึงและ URL ไปยังปลายทางการให้สิทธิ์ของแอปพลิเคชัน ซึ่งจะจัดการการตอบกลับจากเซิร์ฟเวอร์ OAuth 2.0 ของ Google สุดท้าย โค้ดจะตั้งค่าพารามิเตอร์ access_type และ include_granted_scopes ที่ไม่บังคับ
ตัวอย่างเช่น โค้ดนี้จะขอสิทธิ์เข้าถึงข้อมูลเมตาใน Google ไดรฟ์และกิจกรรมในปฏิทินของผู้ใช้แบบอ่านอย่างเดียวและแบบออฟไลน์
import google.oauth2.credentials import google_auth_oauthlib.flow # Required, call the from_client_secrets_file method to retrieve the client ID from a # client_secret.json file. The client ID (from that file) and access scopes are required. (You can # also use the from_client_config method, which passes the client configuration as it originally # appeared in a client secrets file but doesn't access the file itself.) flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file('client_secret.json', scopes=['https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly']) # Required, indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. flow.redirect_uri = 'https://www.example.com/oauth2callback' # Generate URL for request to Google's OAuth 2.0 server. # Use kwargs to set optional request parameters. authorization_url, state = flow.authorization_url( # Recommended, enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Optional, enable incremental authorization. Recommended as a best practice. include_granted_scopes='true', # Optional, if your application knows which user is trying to authenticate, it can use this # parameter to provide a hint to the Google Authentication Server. login_hint='hint@example.com', # Optional, set prompt to 'consent' will prompt the user for consent prompt='consent')
Ruby
ใช้ไฟล์ client_secrets.json ที่คุณสร้างขึ้นเพื่อกำหนดค่าออบเจ็กต์ไคลเอ็นต์ในแอปพลิเคชัน เมื่อกำหนดค่าออบเจ็กต์ไคลเอ็นต์ คุณจะต้องระบุขอบเขตที่แอปพลิเคชันต้องการเข้าถึง พร้อมกับ URL ไปยังปลายทางการตรวจสอบสิทธิ์ของแอปพลิเคชัน ซึ่งจะจัดการการตอบกลับจากเซิร์ฟเวอร์ OAuth 2.0
ตัวอย่างเช่น โค้ดนี้จะขอสิทธิ์เข้าถึงข้อมูลเมตาใน Google ไดรฟ์และกิจกรรมในปฏิทินของผู้ใช้แบบอ่านอย่างเดียวและแบบออฟไลน์
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/drive_v3' require 'google/apis/calendar_v3' # Required, call the from_file method to retrieve the client ID from a # client_secret.json file. client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json') # Required, scope value # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY', 'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY'] # Required, Authorizers require a storage instance to manage long term persistence of # access and refresh tokens. token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new) # Required, indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. callback_uri = '/oauth2callback' # To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI # from the client_secret.json file. To get these credentials for your application, visit # https://console.cloud.google.com/apis/credentials. authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, callback_uri)
แอปพลิเคชันจะใช้ออบเจ็กต์ไคลเอ็นต์เพื่อดำเนินการ OAuth 2.0 เช่น การสร้าง URL คำขอการให้สิทธิ์และการใช้โทเค็นเพื่อการเข้าถึงกับคำขอ HTTP
Node.js
ข้อมูลโค้ดต่อไปนี้จะสร้างออบเจ็กต์ google.auth.OAuth2 ซึ่งกำหนดพารามิเตอร์ในคำขอการให้สิทธิ์
ออบเจ็กต์ดังกล่าวจะใช้ข้อมูลจากไฟล์ client_secret.json เพื่อระบุแอปพลิเคชันของคุณ หากต้องการขอสิทธิ์จากผู้ใช้เพื่อดึงข้อมูลโทเค็นเพื่อการเข้าถึง ให้เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าความยินยอม วิธีสร้าง URL ของหน้าความยินยอม
const {google} = require('googleapis'); const crypto = require('crypto'); const express = require('express'); const session = require('express-session'); /** * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI * from the client_secret.json file. To get these credentials for your application, visit * https://console.cloud.google.com/apis/credentials. */ const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. const scopes = [ 'https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly' ]; // Generate a secure random state value. const state = crypto.randomBytes(32).toString('hex'); // Store state in the session req.session.state = state; // Generate a url that asks permissions for the Drive activity and Google Calendar scope const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true, // Include the state parameter to reduce the risk of CSRF attacks. state: state });
หมายเหตุสำคัญ - ระบบจะแสดงผล refresh_token เฉพาะในการให้สิทธิ์ครั้งแรกเท่านั้น ดูรายละเอียดเพิ่มเติมได้
ที่นี่
HTTP/REST
ปลายทาง OAuth 2.0 ของ Google อยู่ที่ https://accounts.google.com/o/oauth2/v2/auth ปลายทางนี้เข้าถึงได้ผ่าน HTTPS เท่านั้น ระบบจะปฏิเสธการเชื่อมต่อ HTTP แบบธรรมดา
เซิร์ฟเวอร์การให้สิทธิ์ของ Google รองรับพารามิเตอร์สตริงการค้นหาต่อไปนี้สำหรับแอปพลิเคชันเว็บเซิร์ฟเวอร์
| พารามิเตอร์ | |||||||
|---|---|---|---|---|---|---|---|
client_id |
จำเป็น
รหัสไคลเอ็นต์สำหรับแอปพลิเคชันของคุณ คุณดูค่านี้ได้ในหน้าไคลเอ็นต์ของคอนโซล Cloud |
||||||
redirect_uri |
จำเป็น
กำหนดตำแหน่งที่เซิร์ฟเวอร์ API จะเปลี่ยนเส้นทางผู้ใช้หลังจากที่ผู้ใช้ทำขั้นตอนการให้สิทธิ์เสร็จสมบูรณ์ ค่าต้องตรงกับ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตรายการใดรายการหนึ่งสำหรับไคลเอ็นต์ OAuth 2.0 ซึ่งคุณกำหนดค่าไว้ในหน้าไคลเอ็นต์ของ Cloud Console ของไคลเอ็นต์ หากค่านี้ไม่ตรงกับ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตสำหรับ โปรดทราบว่ารูปแบบ |
||||||
response_type |
จำเป็น
กำหนดว่าปลายทาง Google OAuth 2.0 จะแสดงผลรหัสการให้สิทธิ์หรือไม่ ตั้งค่าพารามิเตอร์เป็น |
||||||
scope |
จำเป็น
รายการขอบเขตที่คั่นด้วยช่องว่างซึ่งระบุทรัพยากรที่แอปพลิเคชันของคุณสามารถเข้าถึงในนามของผู้ใช้ ค่าเหล่านี้จะแจ้งหน้าจอขอความยินยอมที่ Google แสดงต่อผู้ใช้ ขอบเขตช่วยให้แอปพลิเคชันขอสิทธิ์เข้าถึงเฉพาะทรัพยากรที่จำเป็นเท่านั้น และยังช่วยให้ผู้ใช้ควบคุมปริมาณสิทธิ์เข้าถึงที่ให้แก่แอปพลิเคชันของคุณได้ด้วย ดังนั้นจึงมีความสัมพันธ์แบบผกผันระหว่างจำนวนขอบเขตที่ขอและแนวโน้มที่จะได้รับความยินยอมของผู้ใช้ เราขอแนะนำให้แอปพลิเคชันของคุณขอสิทธิ์เข้าถึงขอบเขตการให้สิทธิ์ในบริบทเมื่อเป็นไปได้ การขอสิทธิ์เข้าถึงข้อมูลผู้ใช้ในบริบทโดยใช้การให้สิทธิ์แบบเพิ่มขึ้นจะช่วยให้ผู้ใช้เข้าใจว่าเหตุใดแอปพลิเคชันจึงต้องมีสิทธิ์เข้าถึงตามที่ขอ |
||||||
access_type |
แนะนำ
ระบุว่าแอปพลิเคชันของคุณสามารถรีเฟรชโทเค็นเพื่อการเข้าถึงได้หรือไม่เมื่อผู้ใช้ไม่ได้อยู่ที่เบราว์เซอร์ ค่าพารามิเตอร์ที่ถูกต้องคือ ตั้งค่าเป็น |
||||||
state |
แนะนำ
ระบุค่าสตริงที่แอปพลิเคชันใช้เพื่อรักษาสถานะระหว่างคำขอการให้สิทธิ์และการตอบกลับของเซิร์ฟเวอร์การให้สิทธิ์
เซิร์ฟเวอร์จะแสดงผลค่าที่ตรงกับที่คุณส่งเป็นคู่ คุณใช้พารามิเตอร์นี้ได้หลายวัตถุประสงค์ เช่น การนำผู้ใช้ไปยังแหล่งข้อมูลที่ถูกต้องในแอปพลิเคชัน การส่ง Nonce และการลดการปลอมแปลงคำขอแบบข้ามเว็บไซต์ เนื่องจาก |
||||||
include_granted_scopes |
ไม่บังคับ
ช่วยให้แอปพลิเคชันใช้การให้สิทธิ์แบบเพิ่มทีละส่วนเพื่อขอสิทธิ์เข้าถึงขอบเขตเพิ่มเติมในบริบทได้ หากคุณตั้งค่าพารามิเตอร์นี้เป็น |
||||||
enable_granular_consent |
ไม่บังคับ
ค่าเริ่มต้นคือ เมื่อ Google เปิดใช้สิทธิ์แบบละเอียดสำหรับแอปพลิเคชัน พารามิเตอร์นี้จะไม่มีผลอีกต่อไป |
||||||
login_hint |
ไม่บังคับ
หากแอปพลิเคชันทราบว่าผู้ใช้รายใดพยายามตรวจสอบสิทธิ์ ก็สามารถใช้พารามิเตอร์นี้เพื่อระบุคำแนะนำแก่เซิร์ฟเวอร์การตรวจสอบสิทธิ์ของ Google ได้ เซิร์ฟเวอร์จะใช้คำแนะนำเพื่อลดความซับซ้อนของขั้นตอนการเข้าสู่ระบบโดยการป้อนข้อมูลในช่องอีเมลล่วงหน้าในแบบฟอร์มการลงชื่อเข้าใช้ หรือโดยการเลือกเซสชันการเข้าสู่ระบบหลายเซสชันที่เหมาะสม ตั้งค่าพารามิเตอร์เป็นอีเมลหรือตัวระบุ |
||||||
prompt |
ไม่บังคับ
รายการข้อความแจ้งที่คั่นด้วยเว้นวรรคและคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่เพื่อแสดงต่อผู้ใช้ หากคุณไม่ระบุพารามิเตอร์นี้ ระบบจะแจ้งให้ผู้ใช้ทราบเฉพาะในครั้งแรกที่โปรเจ็กต์ของคุณขอสิทธิ์เข้าถึง ดูข้อมูลเพิ่มเติมได้ที่ การแจ้งขอความยินยอมอีกครั้ง ค่าที่เป็นไปได้มีดังนี้
|
||||||
ขั้นตอนที่ 2: เปลี่ยนเส้นทางไปยังเซิร์ฟเวอร์ OAuth 2.0 ของ Google
เปลี่ยนเส้นทางผู้ใช้ไปยังเซิร์ฟเวอร์ OAuth 2.0 ของ Google เพื่อเริ่มกระบวนการตรวจสอบสิทธิ์และการให้สิทธิ์ โดยปกติแล้ว กรณีนี้จะเกิดขึ้นเมื่อแอปพลิเคชันของคุณต้องการเข้าถึงข้อมูลของผู้ใช้เป็นครั้งแรก ในกรณีของการให้สิทธิ์แบบเพิ่มขึ้นทีละส่วน ขั้นตอนนี้จะเกิดขึ้นเมื่อแอปพลิเคชันของคุณต้องการเข้าถึงแหล่งข้อมูลเพิ่มเติมที่ไม่มีสิทธิ์เข้าถึงเป็นครั้งแรกด้วย
PHP
- สร้าง URL เพื่อขอสิทธิ์เข้าถึงจากเซิร์ฟเวอร์ OAuth 2.0 ของ Google โดยทำดังนี้
$auth_url = $client->createAuthUrl(); - เปลี่ยนเส้นทางผู้ใช้ไปยัง
$auth_urlโดยทำดังนี้header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Python
ตัวอย่างนี้แสดงวิธีเปลี่ยนเส้นทางผู้ใช้ไปยัง URL การให้สิทธิ์โดยใช้เฟรมเวิร์กเว็บแอปพลิเคชัน Flask
return flask.redirect(authorization_url)
Ruby
- สร้าง URL เพื่อขอสิทธิ์เข้าถึงจากเซิร์ฟเวอร์ OAuth 2.0 ของ Google โดยทำดังนี้
auth_uri = authorizer.get_authorization_url(request: request)
- เปลี่ยนเส้นทางผู้ใช้ไปยัง
auth_uri
Node.js
-
ใช้ URL
authorizationUrlที่สร้างขึ้นจากเมธอดgenerateAuthUrlในขั้นตอนที่ 1 เพื่อขอสิทธิ์เข้าถึงจากเซิร์ฟเวอร์ OAuth 2.0 ของ Google -
เปลี่ยนเส้นทางผู้ใช้ไปยัง
authorizationUrlres.redirect(authorizationUrl);
HTTP/REST
ตัวอย่างการเปลี่ยนเส้นทางไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google
ตัวอย่าง URL แสดงอยู่ด้านล่าง โดยมีการขึ้นบรรทัดใหม่และเว้นวรรคเพื่อให้อ่านง่าย
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
หลังจากสร้าง URL คำขอแล้ว ให้เปลี่ยนเส้นทางผู้ใช้ไปยัง URL ดังกล่าว
เซิร์ฟเวอร์ OAuth 2.0 ของ Google จะตรวจสอบสิทธิ์ผู้ใช้และขอความยินยอมจากผู้ใช้เพื่อให้แอปพลิเคชันของคุณเข้าถึงขอบเขตที่ขอ ระบบจะส่งการตอบกลับกลับไปยังแอปพลิเคชันของคุณโดยใช้ URL เปลี่ยนเส้นทางที่คุณระบุ
ขั้นตอนที่ 3: Google แจ้งให้ผู้ใช้ให้ความยินยอม
ในขั้นตอนนี้ ผู้ใช้จะตัดสินใจว่าจะให้สิทธิ์เข้าถึงที่ขอแก่แอปพลิเคชันของคุณหรือไม่ ในขั้นตอนนี้ Google จะแสดงหน้าต่างขอความยินยอมซึ่งแสดงชื่อแอปพลิเคชันและบริการ Google API ที่ขอสิทธิ์เข้าถึงด้วยข้อมูลเข้าสู่ระบบการให้สิทธิ์ของผู้ใช้ และสรุปขอบเขตของสิทธิ์เข้าถึงที่จะได้รับ จากนั้นผู้ใช้จะให้ความยินยอมในการให้สิทธิ์เข้าถึงขอบเขตอย่างน้อย 1 รายการที่แอปพลิเคชันของคุณขอหรือปฏิเสธคำขอได้
แอปพลิเคชันของคุณไม่จำเป็นต้องดำเนินการใดๆ ในขั้นตอนนี้ เนื่องจากกำลังรอการตอบกลับจากเซิร์ฟเวอร์ OAuth 2.0 ของ Google ที่ระบุว่ามีการให้สิทธิ์เข้าถึงหรือไม่ เราจะอธิบายการตอบกลับดังกล่าวในขั้นตอนถัดไป
ข้อผิดพลาด
คำขอไปยังปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google อาจแสดงข้อความแสดงข้อผิดพลาดต่อผู้ใช้แทนขั้นตอนการตรวจสอบสิทธิ์และการให้สิทธิ์ที่คาดไว้ รหัสข้อผิดพลาดที่พบบ่อยและวิธีแก้ไขที่แนะนำมีดังนี้
admin_policy_enforced
บัญชี Google ไม่สามารถให้สิทธิ์ขอบเขตที่ขออย่างน้อย 1 รายการเนื่องจากนโยบายของผู้ดูแลระบบ Google Workspace ดูบทความช่วยเหลือสำหรับผู้ดูแลระบบ Google Workspace เรื่อง ควบคุมว่าจะให้แอปของบุคคลที่สามและแอปภายในรายการใดเข้าถึงข้อมูล Google Workspace ได้บ้าง เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ผู้ดูแลระบบอาจจำกัดการเข้าถึงขอบเขตทั้งหมดหรือขอบเขตที่มีความละเอียดอ่อนและถูกจำกัด จนกว่าจะมีการให้สิทธิ์เข้าถึงรหัสไคลเอ็นต์ OAuth ของคุณอย่างชัดเจน
disallowed_useragent
ปลายทางการให้สิทธิ์จะแสดงภายใน User Agent ที่ฝังไว้ซึ่งไม่ได้รับอนุญาตตามนโยบาย OAuth 2.0 ของ Google
นักพัฒนาแอป iOS และ macOS อาจพบข้อผิดพลาดนี้เมื่อเปิดคำขอการให้สิทธิ์ใน WKWebView
นักพัฒนาแอปควรใช้ไลบรารี iOS เช่น Google Sign-In สำหรับ iOS หรือ AppAuth สำหรับ iOS ของ OpenID Foundation แทน
นักพัฒนาเว็บอาจพบข้อผิดพลาดนี้เมื่อแอป iOS หรือ macOS เปิดเว็บลิงก์ทั่วไปใน User Agent ที่ฝังไว้ และผู้ใช้ไปยังปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google จากเว็บไซต์ของคุณ นักพัฒนาแอปควรอนุญาตให้ลิงก์ทั่วไปเปิดในเครื่องมือจัดการลิงก์เริ่มต้นของระบบปฏิบัติการ ซึ่งรวมถึงทั้งเครื่องมือจัดการ Universal Link หรือแอปเบราว์เซอร์เริ่มต้น ไลบรารี SFSafariViewController ก็เป็นตัวเลือกที่รองรับเช่นกัน
org_internal
รหัสไคลเอ็นต์ OAuth ในคำขอเป็นส่วนหนึ่งของโปรเจ็กต์ที่จำกัดการเข้าถึงบัญชี Google ใน องค์กร Google Cloud ที่เฉพาะเจาะจง ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกการกำหนดค่านี้ได้ที่ส่วนประเภทผู้ใช้ในบทความช่วยเหลือเรื่องการตั้งค่าหน้าจอขอความยินยอม OAuth
invalid_client
รหัสลับไคลเอ็นต์ OAuth ไม่ถูกต้อง ตรวจสอบการกำหนดค่าไคลเอ็นต์ OAuth รวมถึงรหัสไคลเอ็นต์และรหัสลับที่ใช้สำหรับคำขอนี้
deleted_client
ไคลเอ็นต์ OAuth ที่ใช้สร้างคำขอถูกลบแล้ว การลบอาจเกิดขึ้นด้วยตนเองหรือโดยอัตโนมัติในกรณีที่ไม่ได้ใช้ไคลเอ็นต์ คุณสามารถกู้คืนลูกค้าที่ลบไปแล้วได้ภายใน 30 วันนับจากวันที่ลบ ดูข้อมูลเพิ่มเติม
invalid_grant
เมื่อรีเฟรชโทเค็นเพื่อการเข้าถึงหรือใช้การให้สิทธิ์แบบเพิ่มขึ้น โทเค็นอาจหมดอายุหรือใช้งานไม่ได้ ตรวจสอบสิทธิ์ผู้ใช้อีกครั้งและขอความยินยอมของผู้ใช้เพื่อรับโทเค็นใหม่ หากยังคงเห็นข้อผิดพลาดนี้อยู่ ให้ตรวจสอบว่าได้กำหนดค่าแอปพลิเคชันอย่างถูกต้อง และคุณใช้โทเค็นและพารามิเตอร์ที่ถูกต้องในคำขอ มิฉะนั้น บัญชีผู้ใช้อาจถูกลบหรือปิดใช้ไปแล้ว
redirect_uri_mismatch
redirect_uri ที่ส่งในคำขอการให้สิทธิ์ไม่ตรงกับ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตสำหรับรหัสไคลเอ็นต์ OAuth ตรวจสอบ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตในหน้าไคลเอ็นต์ของคอนโซล Google Cloud
พารามิเตอร์ redirect_uri อาจหมายถึงขั้นตอน OAuth นอกแบนด์ (OOB) ที่เลิกใช้งานแล้วและไม่รองรับอีกต่อไป ดูคำแนะนำในการย้ายข้อมูลเพื่ออัปเดตการผสานรวม
invalid_request
เกิดข้อผิดพลาดกับคำขอของคุณ ซึ่งอาจเกิดจากสาเหตุหลายประการดังนี้
- คำขอมีรูปแบบไม่ถูกต้อง
- คำขอไม่มีพารามิเตอร์ที่จำเป็น
- คำขอใช้วิธีการให้สิทธิ์ที่ Google ไม่รองรับ ยืนยันว่าการผสานรวม OAuth ของคุณใช้วิธีการผสานรวมที่แนะนำ
ขั้นตอนที่ 4: จัดการการตอบกลับของเซิร์ฟเวอร์ OAuth 2.0
เซิร์ฟเวอร์ OAuth 2.0 จะตอบสนองต่อคำขอเข้าถึงของแอปพลิเคชันโดยใช้ URL ที่ระบุในคำขอ
หากผู้ใช้อนุมัติคำขอเข้าถึง การตอบกลับจะมีรหัสการให้สิทธิ์ หากผู้ใช้ไม่อนุมัติคำขอ การตอบกลับจะมีข้อความแสดงข้อผิดพลาด รหัสการให้สิทธิ์หรือข้อความแสดงข้อผิดพลาดที่ส่งกลับไปยังเว็บเซิร์ฟเวอร์จะปรากฏในสตริงการค้นหา ดังตัวอย่างต่อไปนี้
การตอบกลับข้อผิดพลาด:
https://oauth2.example.com/auth?error=access_denied
การตอบกลับรหัสการให้สิทธิ์:
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
ตัวอย่างการตอบกลับของเซิร์ฟเวอร์ OAuth 2.0
คุณสามารถทดสอบขั้นตอนนี้ได้โดยคลิก URL ตัวอย่างต่อไปนี้ ซึ่งจะขอสิทธิ์เข้าถึงแบบอ่านอย่างเดียวเพื่อดูข้อมูลเมตาของไฟล์ใน Google ไดรฟ์ และสิทธิ์เข้าถึงแบบอ่านอย่างเดียวเพื่อดูกิจกรรมใน Google ปฏิทิน
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
หลังจากทำตามขั้นตอน OAuth 2.0 เสร็จแล้ว เบราว์เซอร์จะเปลี่ยนเส้นทางคุณไปยัง OAuth 2.0 Playground ซึ่งเป็นเครื่องมือสำหรับทดสอบขั้นตอน OAuth คุณจะเห็นว่า OAuth 2.0 Playground ได้บันทึกรหัสการให้สิทธิ์โดยอัตโนมัติ
ขั้นตอนที่ 5: แลกเปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นการรีเฟรชและโทเค็นเพื่อการเข้าถึง
หลังจากได้รับรหัสการให้สิทธิ์แล้ว เว็บเซิร์ฟเวอร์จะแลกรหัสการให้สิทธิ์เป็นโทเค็นเพื่อการเข้าถึงได้
PHP
หากต้องการแลกรหัสการให้สิทธิ์เป็นโทเค็นเพื่อการเข้าถึง ให้ใช้เมธอด fetchAccessTokenWithAuthCode ดังนี้
$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);Python
ในหน้า Callback ให้ใช้ไลบรารี google-auth เพื่อยืนยันการตอบกลับของเซิร์ฟเวอร์การให้สิทธิ์ จากนั้นใช้เมธอด flow.fetch_token เพื่อแลกรหัสการให้สิทธิ์ในการตอบกลับนั้นเป็นโทเค็นเพื่อการเข้าถึง
state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'], state=state) flow.redirect_uri = flask.url_for('oauth2callback', _external=True) authorization_response = flask.request.url flow.fetch_token(authorization_response=authorization_response) # Store the credentials in browser session storage, but for security: client_id, client_secret, # and token_uri are instead stored only on the backend server. credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes}
Ruby
ในหน้า Callback ให้ใช้ไลบรารี googleauth เพื่อยืนยันการตอบกลับของเซิร์ฟเวอร์การให้สิทธิ์ ใช้เมธอด authorizer.handle_auth_callback_deferred เพื่อบันทึกรหัสการให้สิทธิ์และเปลี่ยนเส้นทางกลับไปยัง URL ที่ขอการให้สิทธิ์ตั้งแต่แรก ซึ่งจะเลื่อนการแลกเปลี่ยนรหัสโดยการเก็บผลลัพธ์ไว้ชั่วคราวในเซสชันของผู้ใช้
target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request) redirect target_url
Node.js
หากต้องการแลกรหัสการให้สิทธิ์เป็นโทเค็นเพื่อการเข้าถึง ให้ใช้เมธอด getToken ดังนี้
const url = require('url'); // Receive the callback from Google's OAuth 2.0 server. app.get('/oauth2callback', async (req, res) => { let q = url.parse(req.url, true).query; if (q.error) { // An error response e.g. error=access_denied console.log('Error:' + q.error); } else if (q.state !== req.session.state) { //check state value console.log('State mismatch. Possible CSRF attack'); res.end('State mismatch. Possible CSRF attack'); } else { // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); oauth2Client.setCredentials(tokens); });
HTTP/REST
หากต้องการแลกรหัสการให้สิทธิ์เป็นโทเค็นเพื่อการเข้าถึง ให้เรียกใช้ปลายทาง https://oauth2.googleapis.com/token และตั้งค่าพารามิเตอร์ต่อไปนี้
| ช่อง | |
|---|---|
client_id |
รหัสไคลเอ็นต์ที่ได้จากหน้าไคลเอ็นต์ของ Cloud Console |
client_secret |
ไม่บังคับ
รหัสลับไคลเอ็นต์ที่ได้จากหน้าไคลเอ็นต์ของ Cloud Console |
code |
รหัสการให้สิทธิ์ที่แสดงผลจากคำขอเริ่มต้น |
grant_type |
ตามที่กำหนดไว้ในข้อกำหนด OAuth 2.0 ค่าของช่องนี้ต้องตั้งค่าเป็น authorization_code |
redirect_uri |
URI การเปลี่ยนเส้นทางรายการใดรายการหนึ่งที่แสดงสำหรับโปรเจ็กต์ของคุณในหน้าไคลเอ็นต์ของ Cloud Console สำหรับ client_id ที่ระบุ |
แม้ว่าการใช้ DPoP จะเป็นตัวเลือก แต่เราขอแนะนำให้ใช้เพื่อเพิ่มความปลอดภัย ความปลอดภัยของ DPoP ขึ้นอยู่กับการจำกัดคีย์ส่วนตัวไว้ในอุปกรณ์เดียว เราขอแนะนำให้จัดเก็บคีย์ในลักษณะที่ไม่สามารถคัดลอกออกจากอุปกรณ์ได้ เช่น โดยใช้ TPM, Secure Enclave หรือคีย์สโตร์อื่นๆ ที่สนับสนุนโดยฮาร์ดแวร์ หากต้องการใช้ DPoP แอปพลิเคชันของคุณต้องสร้าง JWT หลักฐาน DPoP ใหม่ที่ไม่ซ้ำกันสำหรับคำขอแต่ละรายการไปยังปลายทางโทเค็น และเพิ่มเป็นส่วนหัวของคำขอ HTTP
| ส่วนหัว | ต้องระบุ | คำอธิบาย |
|---|---|---|
DPoP |
ไม่บังคับ | หลักฐาน DPoP คือ JWT ที่พิสูจน์การครอบครองคีย์ส่วนตัว นี่คือส่วนหัว ไม่ใช่พารามิเตอร์ หากระบุไว้ โทเค็นที่แสดงผลจะเชื่อมโยงกับคีย์นี้ ต้องสร้างหลักฐานใหม่ที่ไม่ซ้ำกันสำหรับคำขอแต่ละรายการ และต้องรวมการอ้างสิทธิ์ htm (เมธอด HTTP) และ htu (HTTP URI) ที่ตรงกับคำขอ |
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างคำขอ
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7& client_id=your_client_id& redirect_uri=https%3A//developers.google.com/oauthplayground& grant_type=authorization_code
สร้างหลักฐาน DPoP
ขั้นตอนต่อไปนี้แสดงวิธีสร้างหลักฐาน DPoP โดยใช้ OpenSSL จากบรรทัดคำสั่ง
- สร้างคู่คีย์ EC P-256
openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
- สร้างส่วนหัว DPoP
ส่วนหัวต้องมีคำกล่าวอ้าง
typ,algและjwk(คีย์สาธารณะ) ค่าxและyคือพิกัดที่เข้ารหัส Base64Url ของคีย์สาธารณะ EC เข้ารหัส Base64Url สำหรับ JSON นี้{ "typ":"dpop+jwt", "alg":"ES256", "jwk": { "kty":"EC", "x":"YOUR_PUBLIC_KEY_X", "y":"YOUR_PUBLIC_KEY_Y", "crv":"P-256" } } - สร้างเพย์โหลด DPoP
เพย์โหลดต้องมี
jti(ตัวระบุที่ไม่ซ้ำกันสำหรับคำขอ),htm(เมธอด HTTP เช่นPOST),htu(HTTP URI เช่นhttps://oauth2.googleapis.com/token) และiat(เวลาที่ออก) หากคุณได้รับ Nonce จากเซิร์ฟเวอร์ในส่วนหัวDPoP-Nonceในการตอบกลับคำขอก่อนหน้า คุณต้องใส่ค่า Nonce นั้นในการอ้างสิทธิ์nonceการอ้างสิทธิ์ Nonce เป็นตัวเลือกสำหรับการแลกเปลี่ยนรหัสการให้สิทธิ์ และจะใช้เมื่อได้รับส่วนหัว DPoP-Nonce ก่อนหน้านี้เท่านั้น เข้ารหัส Base64Url สำหรับ JSON นี้{ "jti":"JTI_VALUE", "htm":"POST", "htu":"https://oauth2.googleapis.com/token", "iat":YOUR_JWT_ISSUED_TIME, "nonce":"SERVER_PROVIDED_NONCE" }ค่า
jtiจะขึ้นอยู่กับประเภทของ Exchange ดังนี้- สำหรับการแลกเปลี่ยนรหัสการให้สิทธิ์
jtiต้องเป็นแฮช SHA256 ที่เข้ารหัส Base64Url ของรหัสการให้สิทธิ์:"jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))" - สำหรับการแลกเปลี่ยนโทเค็นการรีเฟรช
jtiต้องเป็นตัวระบุที่ไม่ซ้ำกันต่อคำขอ:"jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER"
- สำหรับการแลกเปลี่ยนรหัสการให้สิทธิ์
- ลงนามในหลักฐาน:
เชื่อมโยงส่วนหัวและเพย์โหลดที่เข้ารหัสด้วยจุด (
.) จากนั้นลงนามผลลัพธ์ด้วยคีย์ส่วนตัวโดยใช้ ES256 โปรดทราบว่า JWS กำหนดให้ลายเซ็นต้องอยู่ในรูปแบบR | Sที่เชื่อมโยงแบบข้อมูลดิบ (64 ไบต์สำหรับ P-256) หากใช้ OpenSSL โดยตรง คุณต้องแปลงลายเซ็นที่เข้ารหัส ASN.1 DER เริ่มต้นเป็นรูปแบบข้อมูลดิบนี้
การแลกเปลี่ยนที่สำเร็จจะแสดงด้วยการตอบกลับ 200 OK ที่มีโทเค็น หากใช้หลักฐาน DPoP ที่ถูกต้องในระหว่างการแลกเปลี่ยน โทเค็นการรีเฟรชที่ Google แสดงผลจะเชื่อมโยงกับคีย์ของคุณด้วย DPoP แต่โทเค็นเพื่อการเข้าถึงจะไม่เชื่อมโยงกับ DPoP โทเค็นเพื่อการเข้าถึงจะยังคงมี token_type ของ Bearer แทนที่จะเป็น DPoP
นอกจากนี้ Google จะแสดงผลส่วนหัว HTTP DPoP-Nonce ในการตอบกลับด้วย
ไคลเอ็นต์ต้องแคช Nonce นี้และรวมไว้ในการอ้างสิทธิ์ nonce ของหลักฐาน DPoP ในคำขอต่อๆ ไป (เช่น เมื่อแลกเปลี่ยนโทเค็นการรีเฟรชเป็นโทเค็นเพื่อการเข้าถึงใหม่ หรือเมื่อเรียกใช้ API ที่ได้รับการปกป้องด้วย DPoP) การใช้ Nonce ที่ออกก่อนเวลานี้จะช่วยหลีกเลี่ยงความล้มเหลวในการส่งไปกลับเพิ่มเติม (use_dpop_nonce) ในคำขอถัดไปได้
ต้องระบุหลักฐาน DPoP สำหรับคำขอแลกเปลี่ยนโทเค็นที่ส่งด้วยโทเค็นการรีเฟรชที่เชื่อมโยงกับ DPoP
การแลกเปลี่ยนที่ล้มเหลวจะเกิดขึ้นหากไม่มีส่วนหัว DPoP เมื่อคาดไว้ ไม่ถูกต้อง หรือหากหลักฐานใช้คีย์อื่นที่ไม่ใช่คีย์ที่เชื่อมโยงกับโทเค็น ในกรณีเหล่านี้ เซิร์ฟเวอร์จะแสดงข้อผิดพลาด 400 Bad Request
หากหลักฐาน DPoP มีการอ้างสิทธิ์ htm หรือ htu ที่ไม่ตรงกัน, iat ที่หมดอายุ, jti ที่ใช้ซ้ำ หรือลายเซ็นที่ไม่ถูกต้อง Google จะแสดงรหัสข้อผิดพลาด invalid_dpop_proof
หากจำเป็นต้องใช้ Nonce ของ DPoP เช่น ในระหว่างการแลกเปลี่ยนโทเค็นการรีเฟรช และการพิสูจน์ DPoP ไม่มีคำกล่าวอ้าง nonce หรือค่า Nonce ไม่เป็นที่ยอมรับสำหรับเซิร์ฟเวอร์ (เช่น หมดอายุ มีการใช้งานแล้ว หรือไม่ถูกต้อง) Google จะแสดงรหัสข้อผิดพลาด use_dpop_nonce พร้อมกับส่วนหัว HTTP DPoP-Nonce ที่มี Nonce ใหม่ซึ่งคุณสามารถใช้ในคำขอต่อๆ ไปได้
ข้อผิดพลาดอื่นๆ อาจแสดงผลเป็น invalid_grant
Google จะตอบกลับคำขอนี้โดยแสดงผลออบเจ็กต์ JSON ที่มีโทเค็นเพื่อการเข้าถึงที่มีอายุสั้นและโทเค็นการรีเฟรช
โปรดทราบว่าระบบจะแสดงผลโทเค็นการรีเฟรชก็ต่อเมื่อแอปพลิเคชันของคุณตั้งค่าพารามิเตอร์ access_type เป็น offline ในคำขอเริ่มต้นไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google
การตอบกลับจะมีฟิลด์ต่อไปนี้
| ช่อง | |
|---|---|
access_token |
โทเค็นที่แอปพลิเคชันของคุณส่งเพื่อให้สิทธิ์คำขอ Google API |
expires_in |
อายุการใช้งานที่เหลือของโทเค็นเพื่อการเข้าถึงเป็นวินาที |
refresh_token |
โทเค็นที่คุณใช้เพื่อรับโทเค็นเพื่อการเข้าถึงใหม่ได้ โทเค็นการรีเฟรชจะใช้ได้จนกว่าผู้ใช้จะเพิกถอนสิทธิ์เข้าถึงหรือโทเค็นการรีเฟรชหมดอายุ หากใช้ DPoP โทเค็นการรีเฟรชจะเชื่อมโยงกับคีย์ส่วนตัวที่ใช้ในการลงนามหลักฐาน DPoP
ขอย้ำอีกครั้งว่าช่องนี้จะปรากฏในการตอบกลับนี้ก็ต่อเมื่อคุณตั้งค่าพารามิเตอร์ access_type เป็น offline ในคำขอเริ่มต้นไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google
|
refresh_token_expires_in |
อายุการใช้งานที่เหลือของโทเค็นการรีเฟรชเป็นวินาที ระบบจะตั้งค่านี้ก็ต่อเมื่อผู้ใช้ให้สิทธิ์เข้าถึงตามเวลา |
scope |
ขอบเขตของสิทธิ์เข้าถึงที่ access_token มอบให้จะแสดงเป็นรายการสตริงที่คั่นด้วยช่องว่างและคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ |
token_type |
ประเภทของโทเค็นที่แสดงผล ค่านี้จะเป็น Bearer เสมอ แม้ว่าจะใช้ DPoP ก็ตาม |
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างส่วนหัวการตอบกลับและเนื้อหาที่สำเร็จเมื่อใช้ DPoP
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"token_type": "Bearer",
"scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly",
"refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}ข้อผิดพลาด
เมื่อแลกเปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นเพื่อการเข้าถึง คุณอาจพบข้อผิดพลาดต่อไปนี้แทนการตอบกลับที่คาดไว้ รหัสข้อผิดพลาดที่พบบ่อยและวิธีแก้ไขที่แนะนำจะแสดงอยู่ในส่วนนี้
invalid_grant
รหัสการให้สิทธิ์ที่ระบุไม่ถูกต้องหรืออยู่ในรูปแบบที่ไม่ถูกต้อง ขอรหัสใหม่โดยเริ่มกระบวนการ OAuth ใหม่เพื่อแจ้งให้ผู้ใช้ให้ความยินยอมอีกครั้ง
ขั้นตอนที่ 6: ตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์
เมื่อขอสิทธิ์ (ขอบเขต) หลายรายการ ผู้ใช้อาจไม่ให้สิทธิ์เข้าถึงทั้งหมดแก่แอปของคุณ แอปของคุณต้องยืนยันขอบเขตที่ได้รับสิทธิ์จริงๆ และจัดการสถานการณ์ที่สิทธิ์บางอย่างถูกปฏิเสธอย่างเหมาะสม โดยปกติแล้วจะทำได้ด้วยการปิดใช้ฟีเจอร์ที่อาศัยขอบเขตที่ถูกปฏิเสธเหล่านั้น
แต่ก็มีข้อยกเว้น แอป Google Workspace Enterprise ที่มีการมอบสิทธิ์ทั่วทั้งโดเมนหรือแอปที่ทำเครื่องหมายเป็นเชื่อถือได้จะข้ามหน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียด สำหรับแอปเหล่านี้ ผู้ใช้จะไม่เห็นหน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียด แต่แอปของคุณจะได้รับขอบเขตที่ขอทั้งหมดหรือไม่มีเลย
ดูข้อมูลโดยละเอียดเพิ่มเติมได้ที่วิธีจัดการสิทธิ์แบบละเอียด
PHP
หากต้องการตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์ ให้ใช้เมธอด getGrantedScope() ดังนี้
// Space-separated string of granted scopes if it exists, otherwise null. $granted_scopes = $client->getOAuth2Service()->getGrantedScope(); // Determine which scopes user granted and build a dictionary $granted_scopes_dict = [ 'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY), 'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY) ];
Python
ออบเจ็กต์ credentials ที่แสดงผลมีพร็อพเพอร์ตี้ granted_scopes ซึ่งเป็นรายการขอบเขตที่ผู้ใช้ให้สิทธิ์แก่แอปของคุณ
credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes}
ฟังก์ชันต่อไปนี้จะตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์แก่แอปของคุณ
def check_granted_scopes(credentials): features = {} if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']: features['drive'] = True else: features['drive'] = False if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']: features['calendar'] = True else: features['calendar'] = False return features
Ruby
เมื่อขอขอบเขตหลายรายการพร้อมกัน ให้ตรวจสอบว่าขอบเขตใดได้รับสิทธิ์ผ่านพร็อพเพอร์ตี้ scope ของออบเจ็กต์ credentials
# User authorized the request. Now, check which scopes were granted. if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY) # User authorized read-only Drive activity permission. # Calling the APIs, etc else # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly end # Check if user authorized Calendar read permission. if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY) # User authorized Calendar read permission. # Calling the APIs, etc. else # User didn't authorize Calendar read permission. # Update UX and application accordingly end
Node.js
เมื่อขอขอบเขตหลายรายการพร้อมกัน ให้ตรวจสอบว่าขอบเขตใดได้รับสิทธิ์ผ่านพร็อพเพอร์ตี้ scope ของออบเจ็กต์ tokens
// User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly')) { // User authorized read-only Drive activity permission. // Calling the APIs, etc. } else { // User didn't authorize read-only Drive activity permission. // Update UX and application accordingly } // Check if user authorized Calendar read permission. if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. } else { // User didn't authorize Calendar read permission. // Update UX and application accordingly }
HTTP/REST
หากต้องการตรวจสอบว่าผู้ใช้ได้ให้สิทธิ์เข้าถึงขอบเขตที่เฉพาะเจาะจงแก่แอปพลิเคชันของคุณหรือไม่ ให้ตรวจสอบช่อง scope ในการตอบกลับโทเค็นเพื่อการเข้าถึง ขอบเขตของสิทธิ์เข้าถึงที่ได้รับจากโทเค็นเพื่อการเข้าถึง ซึ่งแสดงเป็นรายการสตริงที่คั่นด้วยเว้นวรรคและคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
ตัวอย่างเช่น การตอบกลับโทเค็นเพื่อการเข้าถึงตัวอย่างต่อไปนี้ระบุว่าผู้ใช้ได้ให้สิทธิ์เข้าถึงแอปพลิเคชันของคุณแก่กิจกรรมในไดรฟ์แบบอ่านอย่างเดียวและสิทธิ์กิจกรรมในปฏิทิน
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly", "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
เรียกใช้ Google API
PHP
ใช้โทเค็นเพื่อการเข้าถึงเพื่อเรียกใช้ Google APIs โดยทำตามขั้นตอนต่อไปนี้
- หากต้องการใช้โทเค็นเพื่อการเข้าถึงกับออบเจ็กต์
Google\Clientใหม่ เช่น หากคุณจัดเก็บโทเค็นเพื่อการเข้าถึงไว้ในเซสชันของผู้ใช้ ให้ใช้เมธอดsetAccessTokenดังนี้$client->setAccessToken($access_token); - สร้างออบเจ็กต์บริการสำหรับ API ที่ต้องการเรียกใช้ คุณสร้างออบเจ็กต์บริการโดยระบุออบเจ็กต์
Google\Clientที่ได้รับอนุญาตให้กับเครื่องมือสร้างสำหรับ API ที่ต้องการเรียกใช้ เช่น หากต้องการเรียกใช้ Drive API ให้ทำดังนี้$drive = new Google\Service\Drive($client); - ส่งคำขอไปยังบริการ API โดยใช้
อินเทอร์เฟซที่ออบเจ็กต์บริการมีให้
เช่น หากต้องการแสดงรายการไฟล์ใน Google ไดรฟ์ของผู้ใช้ที่ตรวจสอบสิทธิ์แล้ว ให้ทำดังนี้
$files = $drive->files->listFiles(array());
Python
หลังจากได้รับโทเค็นเพื่อการเข้าถึงแล้ว แอปพลิเคชันจะใช้โทเค็นนั้นเพื่อให้สิทธิ์คำขอ API ในนามของบัญชีผู้ใช้หรือบัญชีบริการที่ระบุได้ ใช้ข้อมูลเข้าสู่ระบบการให้สิทธิ์เฉพาะผู้ใช้เพื่อสร้างออบเจ็กต์บริการสำหรับ API ที่ต้องการเรียกใช้ จากนั้นใช้ออบเจ็กต์นั้นเพื่อส่งคำขอ API ที่ได้รับสิทธิ์
- สร้างออบเจ็กต์บริการสำหรับ API ที่ต้องการเรียกใช้ คุณสร้างออบเจ็กต์บริการโดยเรียกใช้เมธอด
buildของไลบรารีgoogleapiclient.discoveryด้วยชื่อและเวอร์ชันของ API และข้อมูลเข้าสู่ระบบของผู้ใช้ ดังนี้ ตัวอย่างเช่น หากต้องการเรียกใช้ Drive API เวอร์ชัน 3 ให้ทำดังนี้from googleapiclient.discovery import build drive = build('drive', 'v2', credentials=credentials)
- ส่งคำขอไปยังบริการ API โดยใช้อินเทอร์เฟซที่ออบเจ็กต์บริการมีให้
เช่น หากต้องการแสดงรายการไฟล์ใน Google ไดรฟ์ของผู้ใช้ที่ตรวจสอบสิทธิ์แล้ว ให้ทำดังนี้
files = drive.files().list().execute()
Ruby
หลังจากได้รับโทเค็นเพื่อการเข้าถึงแล้ว แอปพลิเคชันจะใช้โทเค็นนั้นเพื่อส่งคำขอ API ในนามของบัญชีผู้ใช้หรือบัญชีบริการที่ระบุได้ ใช้ข้อมูลเข้าสู่ระบบการให้สิทธิ์เฉพาะผู้ใช้เพื่อสร้างออบเจ็กต์บริการสำหรับ API ที่ต้องการเรียกใช้ จากนั้นใช้ออบเจ็กต์นั้นเพื่อส่งคำขอ API ที่ได้รับสิทธิ์
- สร้างออบเจ็กต์บริการสำหรับ API ที่ต้องการเรียกใช้
เช่น หากต้องการเรียกใช้ Drive API เวอร์ชัน 3 ให้ทำดังนี้
drive = Google::Apis::DriveV3::DriveService.new
- ตั้งค่าข้อมูลเข้าสู่ระบบในบริการโดยทำดังนี้
drive.authorization = credentials
- ส่งคำขอไปยังบริการ API โดยใช้อินเทอร์เฟซที่ออบเจ็กต์บริการมีให้
เช่น หากต้องการแสดงรายการไฟล์ใน Google ไดรฟ์ของผู้ใช้ที่ตรวจสอบสิทธิ์แล้ว ให้ทำดังนี้
files = drive.list_files
หรือจะให้สิทธิ์เป็นรายเมธอดก็ได้โดยระบุพารามิเตอร์ options ให้กับเมธอด ดังนี้
files = drive.list_files(options: { authorization: credentials })
Node.js
หลังจากได้รับโทเค็นเพื่อการเข้าถึงและตั้งค่าเป็นออบเจ็กต์ OAuth2 แล้ว ให้ใช้ออบเจ็กต์ดังกล่าวเพื่อเรียกใช้ Google APIs แอปพลิเคชันของคุณสามารถใช้โทเค็นดังกล่าวเพื่อให้สิทธิ์คำขอ API ในนามของบัญชีผู้ใช้หรือบัญชีบริการที่ระบุได้ สร้างออบเจ็กต์บริการสำหรับ API ที่ต้องการเรียกใช้
ตัวอย่างเช่น โค้ดต่อไปนี้ใช้ Google Drive API เพื่อแสดงรายการชื่อไฟล์ในไดรฟ์ของผู้ใช้
const { google } = require('googleapis'); // Example of using Google Drive API to list filenames in user's Drive. const drive = google.drive('v3'); drive.files.list({ auth: oauth2Client, pageSize: 10, fields: 'nextPageToken, files(id, name)', }, (err1, res1) => { if (err1) return console.log('The API returned an error: ' + err1); const files = res1.data.files; if (files.length) { console.log('Files:'); files.map((file) => { console.log(`${file.name} (${file.id})`); }); } else { console.log('No files found.'); } });
HTTP/REST
หลังจากที่แอปพลิเคชันได้รับโทเค็นเพื่อการเข้าถึงแล้ว คุณสามารถใช้โทเค็นดังกล่าวเพื่อเรียกใช้ Google API ในนามของบัญชีผู้ใช้ที่ระบุได้ หากได้รับสิทธิ์เข้าถึงตามขอบเขตที่ API กำหนด โดยใส่โทเค็นเพื่อการเข้าถึงในคำขอไปยัง API โดยใส่พารามิเตอร์การค้นหา access_token หรือค่าส่วนหัว HTTP Bearer Authorization หากเป็นไปได้ เราขอแนะนำให้ใช้ส่วนหัว HTTP เนื่องจากสตริงการค้นหามักจะปรากฏในบันทึกของเซิร์ฟเวอร์ ในกรณีส่วนใหญ่ คุณสามารถใช้ไลบรารีของไคลเอ็นต์เพื่อตั้งค่าการเรียกใช้ Google API (เช่น เมื่อเรียกใช้ Drive Files API)
คุณลองใช้ Google APIs ทั้งหมดและดูขอบเขตได้ที่ OAuth 2.0 Playground
ตัวอย่าง HTTP GET
การเรียกไปยังปลายทาง
drive.files (Drive Files API) โดยใช้ส่วนหัว HTTP Authorization: Bearer อาจมีลักษณะดังต่อไปนี้ โปรดทราบว่าคุณต้องระบุโทเค็นเพื่อการเข้าถึงของคุณเอง ดังนี้
GET /drive/v2/files HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
ต่อไปนี้เป็นการเรียก API เดียวกันสำหรับผู้ใช้ที่ตรวจสอบสิทธิ์แล้วโดยใช้พารามิเตอร์สตริงการค้นหา access_token
GET https://www.googleapis.com/drive/v2/files?access_token=access_token
ตัวอย่างของ curl
คุณทดสอบคำสั่งเหล่านี้ได้ด้วยแอปพลิเคชันบรรทัดคำสั่ง curl ต่อไปนี้คือตัวอย่างที่ใช้ตัวเลือกส่วนหัว HTTP (แนะนำ)
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files
หรือตัวเลือกพารามิเตอร์สตริงการค้นหา
curl https://www.googleapis.com/drive/v2/files?access_token=access_token
ตัวอย่างที่เสร็จสมบูรณ์
ตัวอย่างต่อไปนี้จะพิมพ์รายการไฟล์ใน Google ไดรฟ์ของผู้ใช้ในรูปแบบ JSON หลังจากที่ผู้ใช้ตรวจสอบสิทธิ์และให้ความยินยอมแก่แอปพลิเคชันเพื่อเข้าถึงข้อมูลเมตาในไดรฟ์ของผู้ใช้
PHP
วิธีเรียกใช้ตัวอย่างนี้
- ในคอนโซล API ให้เพิ่ม URL ของเครื่องในพื้นที่ลงในรายการ URL เปลี่ยนเส้นทาง เช่น เพิ่ม
http://localhost:8080 - สร้างไดเรกทอรีใหม่และเปลี่ยนไปใช้ไดเรกทอรีนั้น เช่น
mkdir ~/php-oauth2-example cd ~/php-oauth2-example
- ติดตั้งไลบรารีของไคลเอ็นต์ Google API สำหรับ PHP โดยใช้ Composer ดังนี้
composer require google/apiclient:^2.15.0
- สร้างไฟล์
index.phpและoauth2callback.phpโดยมีเนื้อหาต่อไปนี้ - เรียกใช้ตัวอย่างด้วยเว็บเซิร์ฟเวอร์ทดสอบในตัวของ PHP โดยทำดังนี้
php -S localhost:8080 ~/php-oauth2-example
index.php
<?php require_once __DIR__.'/vendor/autoload.php'; session_start(); $client = new Google\Client(); $client->setAuthConfig('client_secret.json'); // User granted permission as an access token is in the session. if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { $client->setAccessToken($_SESSION['access_token']); // Check if user granted Drive permission if ($_SESSION['granted_scopes_dict']['Drive']) { echo "Drive feature is enabled."; echo "</br>"; $drive = new Drive($client); $files = array(); $response = $drive->files->listFiles(array()); foreach ($response->files as $file) { echo "File: " . $file->name . " (" . $file->id . ")"; echo "</br>"; } } else { echo "Drive feature is NOT enabled."; echo "</br>"; } // Check if user granted Calendar permission if ($_SESSION['granted_scopes_dict']['Calendar']) { echo "Calendar feature is enabled."; echo "</br>"; } else { echo "Calendar feature is NOT enabled."; echo "</br>"; } } else { // Redirect users to outh2call.php which redirects users to Google OAuth 2.0 $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } ?>
oauth2callback.php
<?php require_once __DIR__.'/vendor/autoload.php'; session_start(); $client = new Google\Client(); // Required, call the setAuthConfig function to load authorization credentials from // client_secret.json file. $client->setAuthConfigFile('client_secret.json'); $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF']); // Required, to set the scope value, call the addScope function. $client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]); // Enable incremental authorization. Recommended as a best practice. $client->setIncludeGrantedScopes(true); // Recommended, offline access will give you both an access and refresh token so that // your app can refresh the access token without user interaction. $client->setAccessType("offline"); // Generate a URL for authorization as it doesn't contain code and error if (!isset($_GET['code']) && !isset($_GET['error'])) { // Generate and set state value $state = bin2hex(random_bytes(16)); $client->setState($state); $_SESSION['state'] = $state; // Generate a url that asks permissions. $auth_url = $client->createAuthUrl(); header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL)); } // User authorized the request and authorization code is returned to exchange access and // refresh tokens. if (isset($_GET['code'])) { // Check the state value if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) { die('State mismatch. Possible CSRF attack.'); } // Get access and refresh tokens (if access_type is offline) $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); /** Save access and refresh token to the session variables. * ACTION ITEM: In a production app, you likely want to save the * refresh token in a secure persistent storage instead. */ $_SESSION['access_token'] = $token; $_SESSION['refresh_token'] = $client->getRefreshToken(); // Space-separated string of granted scopes if it exists, otherwise null. $granted_scopes = $client->getOAuth2Service()->getGrantedScope(); // Determine which scopes user granted and build a dictionary $granted_scopes_dict = [ 'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY), 'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY) ]; $_SESSION['granted_scopes_dict'] = $granted_scopes_dict; $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } // An error response e.g. error=access_denied if (isset($_GET['error'])) { echo "Error: ". $_GET['error']; } ?>
Python
ตัวอย่างนี้ใช้เฟรมเวิร์ก Flask โดยจะเรียกใช้เว็บแอปพลิเคชันที่ http://localhost:8080 ซึ่งช่วยให้คุณทดสอบขั้นตอน OAuth 2.0 ได้ หากไปที่ URL ดังกล่าว คุณควรเห็นลิงก์ 5 รายการต่อไปนี้
- เรียกใช้ Drive API: ลิงก์นี้ชี้ไปยังหน้าที่พยายามดำเนินการตามคำขอ API ตัวอย่างหากผู้ใช้ให้สิทธิ์ และจะเริ่มขั้นตอนการให้สิทธิ์หากจำเป็น หากทำสำเร็จ หน้าเว็บจะแสดงการตอบกลับจาก API
- หน้าจำลองเพื่อเรียกใช้ Calendar API: ลิงก์นี้ชี้ไปยังหน้าจำลองที่พยายามดำเนินการตามคำขอ API ตัวอย่างหากผู้ใช้ให้สิทธิ์ หากจำเป็น ระบบจะเริ่มขั้นตอนการให้สิทธิ์ หากทำสำเร็จ หน้าเว็บจะแสดงการตอบกลับจาก API
- ทดสอบขั้นตอนการตรวจสอบสิทธิ์โดยตรง: ลิงก์นี้ชี้ไปยังหน้าที่พยายามส่งผู้ใช้ผ่านขั้นตอนการให้สิทธิ์ แอปจะขอสิทธิ์ส่งคำขอ API ที่ได้รับอนุญาตในนามของผู้ใช้
- เพิกถอนข้อมูลเข้าสู่ระบบปัจจุบัน: ลิงก์นี้จะนำไปยังหน้าที่ เพิกถอนสิทธิ์ที่ผู้ใช้ให้ไว้กับแอปพลิเคชันแล้ว
- ล้างข้อมูลเข้าสู่ระบบของเซสชัน Flask: ลิงก์นี้จะล้างข้อมูลเข้าสู่ระบบการให้สิทธิ์ที่จัดเก็บไว้ในเซสชัน Flask ซึ่งจะช่วยให้คุณเห็นสิ่งที่จะเกิดขึ้นหากผู้ใช้ที่ให้สิทธิ์แก่แอปของคุณแล้วพยายามเรียกใช้คำขอ API ในเซสชันใหม่ นอกจากนี้ยังช่วยให้คุณเห็นการตอบกลับจาก API ที่แอปจะได้รับหากผู้ใช้เพิกถอนสิทธิ์ที่ให้ไว้กับแอป และแอปยังคงพยายามให้สิทธิ์คำขอด้วยโทเค็นเพื่อการเข้าถึงที่เพิกถอนไปแล้ว
# -*- coding: utf-8 -*- import os import flask import json import requests import google.oauth2.credentials import google_auth_oauthlib.flow import googleapiclient.discovery # This variable specifies the name of a file that contains the OAuth 2.0 # information for this application, including its client_id and client_secret. CLIENT_SECRETS_FILE = "client_secret.json" # The OAuth 2.0 access scope allows for access to the # authenticated user's account and requires requests to use an SSL connection. SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly'] API_SERVICE_NAME = 'drive' API_VERSION = 'v2' app = flask.Flask(__name__) # Note: A secret key is included in the sample so that it works. # If you use this code in your application, replace this with a truly secret # key. See https://flask.palletsprojects.com/quickstart/#sessions. app.secret_key = 'REPLACE ME - this value is here as a placeholder.' @app.route('/') def index(): return print_index_table() @app.route('/drive') def drive_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') features = flask.session['features'] if features['drive']: # Load client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from browser session storage. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) drive = googleapiclient.discovery.build( API_SERVICE_NAME, API_VERSION, credentials=credentials) files = drive.files().list().execute() # Save credentials back to session in case access token was refreshed. flask.session['credentials'] = credentials_to_dict(credentials) return flask.jsonify(**files) else: # User didn't authorize read-only Drive activity permission. return '<p>Drive feature is not enabled.</p>' @app.route('/calendar') def calendar_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') features = flask.session['features'] if features['calendar']: # User authorized Calendar read permission. # Calling the APIs, etc. return ('<p>User granted the Google Calendar read permission. '+ 'This sample code does not include code to call Calendar</p>') else: # User didn't authorize Calendar read permission. # Update UX and application accordingly return '<p>Calendar feature is not enabled.</p>' @app.route('/authorize') def authorize(): # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps. flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES) # The URI created here must exactly match one of the authorized redirect URIs # for the OAuth 2.0 client, which you configured in the API Console. If this # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch' # error. flow.redirect_uri = flask.url_for('oauth2callback', _external=True) authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true') # Store the state so the callback can verify the auth server response. flask.session['state'] = state return flask.redirect(authorization_url) @app.route('/oauth2callback') def oauth2callback(): # Specify the state when creating the flow in the callback so that it can # verified in the authorization server response. state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES, state=state) flow.redirect_uri = flask.url_for('oauth2callback', _external=True) # Use the authorization server's response to fetch the OAuth 2.0 tokens. authorization_response = flask.request.url flow.fetch_token(authorization_response=authorization_response) # Store credentials in the session. # ACTION ITEM: In a production app, you likely want to save these # credentials in a persistent database instead. credentials = flow.credentials credentials = credentials_to_dict(credentials) flask.session['credentials'] = credentials # Check which scopes user granted features = check_granted_scopes(credentials) flask.session['features'] = features return flask.redirect('/') @app.route('/revoke') def revoke(): if 'credentials' not in flask.session: return ('You need to <a href="/authorize">authorize</a> before ' + 'testing the code to revoke credentials.') # Load client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from the session. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) revoke = requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'}) status_code = getattr(revoke, 'status_code') if status_code == 200: # Clear the user's session credentials after successful revocation if 'credentials' in flask.session: del flask.session['credentials'] del flask.session['features'] return('Credentials successfully revoked.' + print_index_table()) else: return('An error occurred.' + print_index_table()) @app.route('/clear') def clear_credentials(): if 'credentials' in flask.session: del flask.session['credentials'] return ('Credentials have been cleared.<br><br>' + print_index_table()) def credentials_to_dict(credentials): return {'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes} def check_granted_scopes(credentials): features = {} if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']: features['drive'] = True else: features['drive'] = False if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']: features['calendar'] = True else: features['calendar'] = False return features def print_index_table(): return ('<table>' + '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' + '<td>Go directly to the authorization flow. If there are stored ' + ' credentials, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/drive">Call Drive API directly</a></td>' + '<td> Use stored credentials to call the API, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/calendar">Call Calendar API directly</a></td>' + '<td> Use stored credentials to call the API, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/revoke">Revoke current credentials</a></td>' + '<td>Revoke the access token associated with the current user ' + ' session. After revoking credentials, if you go to the test ' + ' page, you should see an <code>invalid_grant</code> error.' + '</td></tr>' + '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' + '<td>Clear the access token currently stored in the user session. ' + ' After clearing the token, if you <a href="/authorize">authorize</a> ' + ' again, you should go back to the auth flow.' + '</td></tr></table>') if __name__ == '__main__': # When running locally, disable OAuthlib's HTTPs verification. # ACTION ITEM for developers: # When running in production *do not* leave this option enabled. os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # This disables the requested scopes and granted scopes check. # If users only grant partial request, the warning would not be thrown. os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1' # Specify a hostname and port that are set as a valid redirect URI # for your API project in the Google API Console. app.run('localhost', 8080, debug=True)
Ruby
ตัวอย่างนี้ใช้เฟรมเวิร์ก Sinatra
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/drive_v3' require 'google/apis/calendar_v3' require 'sinatra' configure do enable :sessions # Required, call the from_file method to retrieve the client ID from a # client_secret.json file. set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json') # Required, scope value # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY', 'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY'] # Required, Authorizers require a storage instance to manage long term persistence of # access and refresh tokens. set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new) # Required, indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. set :callback_uri, '/oauth2callback' # To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI # from the client_secret.json file. To get these credentials for your application, visit # https://console.cloud.google.com/apis/credentials. set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope, settings.token_store, callback_uri: settings.callback_uri) end get '/' do # NOTE: Assumes the user is already authenticated to the app user_id = request.session['user_id'] # Fetch stored credentials for the user from the given request session. # nil if none present credentials = settings.authorizer.get_credentials(user_id, request) if credentials.nil? # Generate a url that asks the user to authorize requested scope(s). # Then, redirect user to the url. redirect settings.authorizer.get_authorization_url(request: request) end # User authorized the request. Now, check which scopes were granted. if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY) # User authorized read-only Drive activity permission. # Example of using Google Drive API to list filenames in user's Drive. drive = Google::Apis::DriveV3::DriveService.new files = drive.list_files(options: { authorization: credentials }) "<pre>#{JSON.pretty_generate(files.to_h)}</pre>" else # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly end # Check if user authorized Calendar read permission. if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY) # User authorized Calendar read permission. # Calling the APIs, etc. else # User didn't authorize Calendar read permission. # Update UX and application accordingly end end # Receive the callback from Google's OAuth 2.0 server. get '/oauth2callback' do # Handle the result of the oauth callback. Defers the exchange of the code by # temporarily stashing the results in the user's session. target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request) redirect target_url end
Node.js
วิธีเรียกใช้ตัวอย่างนี้
-
ในคอนโซล API ให้เพิ่ม URL ของเครื่องในพื้นที่ลงในรายการ URL เปลี่ยนเส้นทาง เช่น เพิ่ม
http://localhost - ตรวจสอบว่าคุณได้ติดตั้ง LTS สำหรับการบำรุงรักษา, LTS ที่ใช้งานอยู่ หรือ Node.js เวอร์ชันปัจจุบันแล้ว
-
สร้างไดเรกทอรีใหม่และเปลี่ยนไปใช้ไดเรกทอรีนั้น เช่น
mkdir ~/nodejs-oauth2-example cd ~/nodejs-oauth2-example
-
ติดตั้งไลบรารีของไคลเอ็นต์ Google API สำหรับ Node.js โดยใช้ npm ดังนี้
npm install googleapis
-
สร้างไฟล์
main.jsที่มีเนื้อหาต่อไปนี้ -
เรียกใช้ตัวอย่าง
node .\main.js
main.js
const http = require('http'); const https = require('https'); const url = require('url'); const { google } = require('googleapis'); const crypto = require('crypto'); const express = require('express'); const session = require('express-session'); /** * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI. * To get these credentials for your application, visit * https://console.cloud.google.com/apis/credentials. */ const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. const scopes = [ 'https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly' ]; /* Global variable that stores user credential in this code example. * ACTION ITEM for developers: * Store user's refresh token in your data store if * incorporating this code into your real app. * For more information on handling refresh tokens, * see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens */ let userCredential = null; async function main() { const app = express(); app.use(session({ secret: 'your_secure_secret_key', // Replace with a strong secret resave: false, saveUninitialized: false, })); // Example on redirecting user to Google's OAuth 2.0 server. app.get('/', async (req, res) => { // Generate a secure random state value. const state = crypto.randomBytes(32).toString('hex'); // Store state in the session req.session.state = state; // Generate a url that asks permissions for the Drive activity and Google Calendar scope const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true, // Include the state parameter to reduce the risk of CSRF attacks. state: state }); res.redirect(authorizationUrl); }); // Receive the callback from Google's OAuth 2.0 server. app.get('/oauth2callback', async (req, res) => { // Handle the OAuth 2.0 server response let q = url.parse(req.url, true).query; if (q.error) { // An error response e.g. error=access_denied console.log('Error:' + q.error); } else if (q.state !== req.session.state) { //check state value console.log('State mismatch. Possible CSRF attack'); res.end('State mismatch. Possible CSRF attack'); } else { // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); oauth2Client.setCredentials(tokens); /** Save credential to the global variable in case access token was refreshed. * ACTION ITEM: In a production app, you likely want to save the refresh token * in a secure persistent database instead. */ userCredential = tokens; // User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly')) { // User authorized read-only Drive activity permission. // Example of using Google Drive API to list filenames in user's Drive. const drive = google.drive('v3'); drive.files.list({ auth: oauth2Client, pageSize: 10, fields: 'nextPageToken, files(id, name)', }, (err1, res1) => { if (err1) return console.log('The API returned an error: ' + err1); const files = res1.data.files; if (files.length) { console.log('Files:'); files.map((file) => { console.log(`${file.name} (${file.id})`); }); } else { console.log('No files found.'); } }); } else { // User didn't authorize read-only Drive activity permission. // Update UX and application accordingly } // Check if user authorized Calendar read permission. if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. } else { // User didn't authorize Calendar read permission. // Update UX and application accordingly } } }); // Example on revoking a token app.get('/revoke', async (req, res) => { // Build the string for the POST request let postData = "token=" + userCredential.access_token; // Options for POST request to Google's OAuth 2.0 server to revoke a token let postOptions = { host: 'oauth2.googleapis.com', port: '443', path: '/revoke', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; // Set up the request const postReq = https.request(postOptions, function (res) { res.setEncoding('utf8'); res.on('data', d => { console.log('Response: ' + d); }); }); postReq.on('error', error => { console.log(error) }); // Post the request with data postReq.write(postData); postReq.end(); }); const server = http.createServer(app); server.listen(8080); } main().catch(console.error);
HTTP/REST
ตัวอย่าง Python นี้ใช้เฟรมเวิร์ก Flask และไลบรารี Requests เพื่อสาธิตขั้นตอนการทำงานของเว็บ OAuth 2.0 เราขอแนะนำให้ใช้ไลบรารีของไคลเอ็นต์ Google API สำหรับ Python ในขั้นตอนนี้ (ตัวอย่างในแท็บ Python ใช้ไลบรารีของไคลเอ็นต์)
import json import flask import requests app = flask.Flask(__name__) # To get these credentials (CLIENT_ID CLIENT_SECRET) and for your application, visit # https://console.cloud.google.com/apis/credentials. CLIENT_ID = '123456789.apps.googleusercontent.com' CLIENT_SECRET = 'abc123' # Read from a file or environmental variable in a real app # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly' # Indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. REDIRECT_URI = 'http://example.com/oauth2callback' @app.route('/') def index(): if 'credentials' not in flask.session: return flask.redirect(flask.url_for('oauth2callback')) credentials = json.loads(flask.session['credentials']) if credentials['expires_in'] <= 0: return flask.redirect(flask.url_for('oauth2callback')) else: # User authorized the request. Now, check which scopes were granted. if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['scope']: # User authorized read-only Drive activity permission. # Example of using Google Drive API to list filenames in user's Drive. headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])} req_uri = 'https://www.googleapis.com/drive/v2/files' r = requests.get(req_uri, headers=headers).text else: # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly r = 'User did not authorize Drive permission.' # Check if user authorized Calendar read permission. if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['scope']: # User authorized Calendar read permission. # Calling the APIs, etc. r += 'User authorized Calendar permission.' else: # User didn't authorize Calendar read permission. # Update UX and application accordingly r += 'User did not authorize Calendar permission.' return r @app.route('/oauth2callback') def oauth2callback(): if 'code' not in flask.request.args: state = str(uuid.uuid4()) flask.session['state'] = state # Generate a url that asks permissions for the Drive activity # and Google Calendar scope. Then, redirect user to the url. auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code' '&client_id={}&redirect_uri={}&scope={}&state={}').format(CLIENT_ID, REDIRECT_URI, SCOPE, state) return flask.redirect(auth_uri) else: if 'state' not in flask.request.args or flask.request.args['state'] != flask.session['state']: return 'State mismatch. Possible CSRF attack.', 400 auth_code = flask.request.args.get('code') data = {'code': auth_code, 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'redirect_uri': REDIRECT_URI, 'grant_type': 'authorization_code'} # Exchange authorization code for access and refresh tokens (if access_type is offline) r = requests.post('https://oauth2.googleapis.com/token', data=data) flask.session['credentials'] = r.text return flask.redirect(flask.url_for('index')) if __name__ == '__main__': import uuid app.secret_key = str(uuid.uuid4()) app.debug = False app.run()
กฎการตรวจสอบ URI การเปลี่ยนเส้นทาง
Google ใช้กฎการตรวจสอบต่อไปนี้กับ URI การเปลี่ยนเส้นทางเพื่อช่วยนักพัฒนาแอปดูแลให้แอปพลิเคชันปลอดภัย URI เปลี่ยนเส้นทางต้องเป็นไปตามกฎเหล่านี้ ดูคำจำกัดความของโดเมน โฮสต์ เส้นทาง การค้นหา รูปแบบ และข้อมูลผู้ใช้ที่ใช้ในกฎเหล่านี้ได้ที่ RFC 3986 ส่วนที่ 3
| กฎการตรวจสอบความถูกต้อง | |
|---|---|
| รูปแบบ |
URI เปลี่ยนเส้นทางต้องใช้รูปแบบ HTTPS ไม่ใช่ HTTP ธรรมดา URI ของ Localhost (รวมถึง URI ของที่อยู่ IP ของ Localhost) จะได้รับการยกเว้นจากกฎนี้ |
| ผู้จัด |
โฮสต์ต้องไม่ใช่ที่อยู่ IP ดิบ ที่อยู่ IP ของ Localhost ได้รับการยกเว้นจากกฎนี้ |
| โดเมน |
“googleusercontent.com”goo.gl) เว้นแต่ว่าแอปจะเป็นเจ้าของโดเมน นอกจากนี้ หากแอปที่เป็นเจ้าของโดเมนเครื่องมือย่อ URL เลือกที่จะเปลี่ยนเส้นทางไปยังโดเมนนั้น URI การเปลี่ยนเส้นทางดังกล่าวต้องมี “/google-callback/” ในเส้นทางหรือลงท้ายด้วย “/google-callback” |
| Userinfo |
URI เปลี่ยนเส้นทางต้องไม่มีองค์ประกอบย่อย userinfo |
| เส้นทาง |
URI การเปลี่ยนเส้นทางต้องไม่มี Path Traversal (หรือที่เรียกว่า Directory Backtracking) ซึ่งแสดงด้วย |
| การค้นหา |
URI การเปลี่ยนเส้นทางต้องไม่มีการเปลี่ยนเส้นทางแบบเปิด |
| Fragment |
URI การเปลี่ยนเส้นทางต้องไม่มีคอมโพเนนต์ Fragment |
| อักขระ |
URI การเปลี่ยนเส้นทางต้องไม่มีอักขระบางตัว ซึ่งรวมถึง
|
การให้สิทธิ์แบบเพิ่มทีละส่วน
ในโปรโตคอล OAuth 2.0 แอปของคุณจะขอสิทธิ์เข้าถึงทรัพยากร ซึ่งระบุตามขอบเขต แนวทางปฏิบัติแนะนำด้านประสบการณ์ของผู้ใช้คือการขอสิทธิ์เข้าถึงทรัพยากรในเวลาที่คุณต้องการ เซิร์ฟเวอร์การให้สิทธิ์ของ Google รองรับการให้สิทธิ์แบบเพิ่มทีละส่วนเพื่อให้สามารถดำเนินการดังกล่าวได้ ฟีเจอร์นี้ช่วยให้คุณขอขอบเขตได้ตามต้องการ และหากผู้ใช้ให้สิทธิ์สำหรับขอบเขตใหม่ ระบบจะแสดงผลรหัสการให้สิทธิ์ที่อาจแลกเปลี่ยนเป็นโทเค็นที่มีขอบเขตทั้งหมดที่ผู้ใช้ให้สิทธิ์แก่โปรเจ็กต์
ตัวอย่างเช่น แอปที่ให้ผู้ใช้ฟังตัวอย่างแทร็กเพลงและสร้างมิกซ์อาจต้องการทรัพยากรเพียงไม่กี่รายการเมื่อลงชื่อเข้าใช้ ซึ่งอาจเป็นเพียงชื่อของผู้ใช้ที่ลงชื่อเข้าใช้เท่านั้น อย่างไรก็ตาม การบันทึกมิกซ์ที่เสร็จสมบูรณ์จะต้องมีสิทธิ์เข้าถึง Google ไดรฟ์ของผู้ใช้ ผู้ใช้ส่วนใหญ่จะรู้สึกว่าเป็นเรื่องปกติหากระบบขอสิทธิ์เข้าถึง Google ไดรฟ์เฉพาะเมื่อแอปจำเป็นต้องใช้จริงๆ เท่านั้น
ในกรณีนี้ เมื่อลงชื่อเข้าใช้ แอปอาจขอขอบเขต openid และ profile เพื่อลงชื่อเข้าใช้ขั้นพื้นฐาน จากนั้นจึงขอขอบเขต https://www.googleapis.com/auth/drive.file ในภายหลังเมื่อมีการส่งคำขอแรกเพื่อบันทึกมิกซ์
หากต้องการใช้การให้สิทธิ์แบบเพิ่มขึ้น ให้ทำตามขั้นตอนปกติในการขอโทเค็นเพื่อการเข้าถึง แต่ตรวจสอบว่าคำขอการให้สิทธิ์มีขอบเขตที่ได้รับสิทธิ์ก่อนหน้านี้ วิธีนี้ช่วยให้แอปของคุณไม่ต้องจัดการโทเค็นเพื่อการเข้าถึงหลายรายการ
กฎต่อไปนี้ใช้กับโทเค็นเพื่อการเข้าถึงที่ได้จากการให้สิทธิ์แบบเพิ่มขึ้น
- โทเค็นนี้สามารถใช้เพื่อเข้าถึงทรัพยากรที่สอดคล้องกับขอบเขตใดก็ได้ที่รวมอยู่ในการให้สิทธิ์แบบรวมใหม่
- เมื่อคุณใช้โทเค็นการรีเฟรชสำหรับการให้สิทธิ์แบบรวมเพื่อรับโทเค็นเพื่อการเข้าถึง โทเค็นเพื่อการเข้าถึงจะแสดงถึงการให้สิทธิ์แบบรวมและสามารถใช้กับค่า
scopeใดก็ได้ที่รวมอยู่ในการตอบกลับ - การให้สิทธิ์แบบรวมจะรวมขอบเขตทั้งหมดที่ผู้ใช้ให้สิทธิ์แก่โปรเจ็กต์ API แม้ว่าคำขอให้สิทธิ์จะมาจากไคลเอ็นต์ที่ต่างกันก็ตาม ตัวอย่างเช่น หากผู้ใช้ให้สิทธิ์เข้าถึงขอบเขตหนึ่งโดยใช้ไคลเอ็นต์เดสก์ท็อปของแอปพลิเคชัน แล้วให้สิทธิ์เข้าถึงอีกขอบเขตหนึ่งแก่แอปพลิเคชันเดียวกันผ่านไคลเอ็นต์มือถือ การให้สิทธิ์แบบรวมจะรวมทั้ง 2 ขอบเขต
- หากคุณเพิกถอนโทเค็นที่แสดงถึงการให้สิทธิ์แบบรวม ระบบจะเพิกถอนสิทธิ์เข้าถึงขอบเขตทั้งหมดของการให้สิทธิ์นั้นในนามของผู้ใช้ที่เชื่อมโยงพร้อมกัน
ตัวอย่างโค้ดเฉพาะภาษาในขั้นตอนที่ 1: ตั้งค่าการให้สิทธิ์เปลี่ยนเส้นทางไปยังเซิร์ฟเวอร์ OAuth 2.0 ของ Google ทั้งหมดใช้การให้สิทธิ์แบบเพิ่มทีละส่วน ตัวอย่างโค้ดต่อไปนี้ยังแสดงโค้ดที่คุณต้องเพิ่มเพื่อใช้การให้สิทธิ์แบบเพิ่มส่วนด้วย
PHP
$client->setIncludeGrantedScopes(true);Python
ใน Python ให้ตั้งค่าอาร์กิวเมนต์คีย์เวิร์ด include_granted_scopes เป็น true เพื่อให้มั่นใจว่าคำขอการให้สิทธิ์รวมขอบเขตที่ได้รับสิทธิ์ก่อนหน้านี้ เป็นไปได้อย่างยิ่งว่า include_granted_scopes จะไม่ใช่อาร์กิวเมนต์คีย์เวิร์ดเพียงรายการเดียวที่คุณตั้งค่าไว้ ดังที่แสดงในตัวอย่างด้านล่าง
authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true')
Ruby
auth_client.update!( :additional_parameters => {"include_granted_scopes" => "true"} )
Node.js
const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true });
HTTP/REST
GET https://accounts.google.com/o/oauth2/v2/auth? client_id=your_client_id& response_type=code& state=state_parameter_passthrough_value& scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& redirect_uri=https%3A//developers.google.com/oauthplayground& prompt=consent& include_granted_scopes=true
รีเฟรชโทเค็นเพื่อการเข้าถึง (การเข้าถึงแบบออฟไลน์)
โทเค็นเพื่อการเข้าถึงจะหมดอายุเป็นระยะๆ และกลายเป็นข้อมูลเข้าสู่ระบบที่ไม่ถูกต้องสำหรับคำขอ API ที่เกี่ยวข้อง คุณสามารถรีเฟรชโทเค็นเพื่อการเข้าถึงได้โดยไม่ต้องขอสิทธิ์จากผู้ใช้ (รวมถึงเมื่อผู้ใช้ไม่ได้อยู่ด้วย) หากคุณขอสิทธิ์เข้าถึงแบบออฟไลน์สำหรับขอบเขตที่เชื่อมโยงกับโทเค็น
- หากคุณใช้ไลบรารีของไคลเอ็นต์ Google API ออบเจ็กต์ไคลเอ็นต์จะรีเฟรชโทเค็นเพื่อการเข้าถึงตามที่จำเป็น ตราบใดที่คุณกำหนดค่าออบเจ็กต์นั้นสำหรับการเข้าถึงแบบออฟไลน์
- หากไม่ได้ใช้ไลบรารีของไคลเอ็นต์ คุณต้องตั้งค่าพารามิเตอร์การค้นหา HTTP
access_typeเป็นofflineเมื่อเปลี่ยนเส้นทางผู้ใช้ไปยังเซิร์ฟเวอร์ OAuth 2.0 ของ Google ในกรณีนี้ เซิร์ฟเวอร์การให้สิทธิ์ของ Google จะแสดงผลโทเค็นการรีเฟรชเมื่อคุณแลกเปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นเพื่อการเข้าถึง จากนั้น หากโทเค็นเพื่อการเข้าถึงหมดอายุ (หรือเมื่อใดก็ตาม) คุณสามารถใช้โทเค็นการรีเฟรชเพื่อรับโทเค็นเพื่อการเข้าถึงใหม่ได้
การขอสิทธิ์เข้าถึงแบบออฟไลน์เป็นข้อกำหนดสำหรับแอปพลิเคชันที่ต้องการเข้าถึง Google API เมื่อผู้ใช้ไม่ได้อยู่ ตัวอย่างเช่น แอปที่ให้บริการสำรองข้อมูลหรือดำเนินการตามเวลาที่กำหนดไว้ล่วงหน้าจะต้องรีเฟรชโทเค็นเพื่อการเข้าถึงได้เมื่อผู้ใช้ไม่ได้อยู่หน้าจอ รูปแบบการเข้าถึงเริ่มต้นเรียกว่า online
เว็บแอปพลิเคชันฝั่งเซิร์ฟเวอร์ แอปพลิเคชันที่ติดตั้ง และอุปกรณ์ทั้งหมดจะได้รับโทเค็นการรีเฟรชในระหว่างกระบวนการให้สิทธิ์ โดยทั่วไปแล้ว โทเค็นการรีเฟรชจะไม่ใช้ในเว็บแอปพลิเคชันฝั่งไคลเอ็นต์ (JavaScript)
PHP
หากแอปพลิเคชันของคุณต้องการสิทธิ์เข้าถึง Google API แบบออฟไลน์ ให้ตั้งค่าประเภทการเข้าถึงของไคลเอ็นต์ API เป็น offline ดังนี้
$client->setAccessType("offline");หลังจากผู้ใช้ให้สิทธิ์เข้าถึงแบบออฟไลน์สำหรับขอบเขตที่ขอแล้ว คุณจะใช้ไคลเอ็นต์ API เพื่อเข้าถึง Google APIs ในนามของผู้ใช้ต่อไปได้เมื่อผู้ใช้ออฟไลน์ ออบเจ็กต์ไคลเอ็นต์จะรีเฟรชโทเค็นเพื่อการเข้าถึงตามที่จำเป็น
Python
ใน Python ให้ตั้งค่าอาร์กิวเมนต์คีย์เวิร์ด access_type เป็น offline เพื่อให้แน่ใจว่าคุณจะรีเฟรชโทเค็นเพื่อการเข้าถึงได้โดยไม่ต้องแจ้งให้ผู้ใช้ขอสิทธิ์อีกครั้ง เป็นไปได้อย่างยิ่งว่า access_type จะไม่ใช่อาร์กิวเมนต์คีย์เวิร์ดเพียงรายการเดียวที่คุณตั้งค่าไว้ ดังที่แสดงในตัวอย่างด้านล่าง
authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true')
หลังจากผู้ใช้ให้สิทธิ์เข้าถึงแบบออฟไลน์สำหรับขอบเขตที่ขอแล้ว คุณจะใช้ไคลเอ็นต์ API เพื่อเข้าถึง Google APIs ในนามของผู้ใช้ต่อไปได้เมื่อผู้ใช้ออฟไลน์ ออบเจ็กต์ไคลเอ็นต์จะรีเฟรชโทเค็นเพื่อการเข้าถึงตามที่จำเป็น
Ruby
หากแอปพลิเคชันของคุณต้องการสิทธิ์เข้าถึง Google API แบบออฟไลน์ ให้ตั้งค่าประเภทการเข้าถึงของไคลเอ็นต์ API เป็น offline ดังนี้
auth_client.update!( :additional_parameters => {"access_type" => "offline"} )
หลังจากผู้ใช้ให้สิทธิ์เข้าถึงแบบออฟไลน์สำหรับขอบเขตที่ขอแล้ว คุณจะใช้ไคลเอ็นต์ API เพื่อเข้าถึง Google APIs ในนามของผู้ใช้ต่อไปได้เมื่อผู้ใช้ออฟไลน์ ออบเจ็กต์ไคลเอ็นต์จะรีเฟรชโทเค็นเพื่อการเข้าถึงตามที่จำเป็น
Node.js
หากแอปพลิเคชันของคุณต้องการสิทธิ์เข้าถึง Google API แบบออฟไลน์ ให้ตั้งค่าประเภทการเข้าถึงของไคลเอ็นต์ API เป็น offline ดังนี้
const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true });
หลังจากผู้ใช้ให้สิทธิ์เข้าถึงแบบออฟไลน์สำหรับขอบเขตที่ขอแล้ว คุณจะใช้ไคลเอ็นต์ API เพื่อเข้าถึง Google APIs ในนามของผู้ใช้ต่อไปได้เมื่อผู้ใช้ออฟไลน์ ออบเจ็กต์ไคลเอ็นต์จะรีเฟรชโทเค็นเพื่อการเข้าถึงตามที่จำเป็น
โทเค็นเพื่อการเข้าถึงหมดอายุ ไลบรารีนี้จะใช้โทเค็นการรีเฟรชโดยอัตโนมัติเพื่อรับโทเค็นเพื่อการเข้าถึงใหม่หากโทเค็นเดิมใกล้หมดอายุ วิธีง่ายๆ ในการตรวจสอบว่าคุณจัดเก็บโทเค็นล่าสุดอยู่เสมอคือการใช้เหตุการณ์โทเค็น ดังนี้
oauth2Client.on('tokens', (tokens) => { if (tokens.refresh_token) { // store the refresh_token in your secure persistent database console.log(tokens.refresh_token); } console.log(tokens.access_token); });
เหตุการณ์โทเค็นนี้จะเกิดขึ้นในการให้สิทธิ์ครั้งแรกเท่านั้น และคุณต้องตั้งค่า access_type เป็น offline เมื่อเรียกใช้เมธอด generateAuthUrl เพื่อรับโทเค็นการรีเฟรช หากคุณให้สิทธิ์ที่จำเป็นแก่แอปแล้วโดยไม่ได้ตั้งค่าข้อจำกัดที่เหมาะสมสำหรับการรับโทเค็นการรีเฟรช คุณจะต้องให้สิทธิ์แอปพลิเคชันอีกครั้งเพื่อรับโทเค็นการรีเฟรชใหม่
หากต้องการตั้งค่า refresh_token ในภายหลัง คุณสามารถใช้วิธี setCredentials ได้ ดังนี้
oauth2Client.setCredentials({ refresh_token: `STORED_REFRESH_TOKEN` });
เมื่อไคลเอ็นต์มีโทเค็นการรีเฟรชแล้ว ระบบจะรับและรีเฟรชโทเค็นเพื่อการเข้าถึงโดยอัตโนมัติในการเรียก API ครั้งถัดไป
HTTP/REST
หากต้องการรีเฟรชโทเค็นเพื่อการเข้าถึง แอปพลิเคชันของคุณจะส่งคำขอ HTTPS POST ไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google (https://oauth2.googleapis.com/token) ซึ่งมีพารามิเตอร์ต่อไปนี้ในเนื้อหาคำขอ
| ชื่อ | ค่า |
|---|---|
client_id |
รหัสไคลเอ็นต์ที่ได้จากคอนโซล API |
client_secret |
ไม่บังคับ
รหัสลับไคลเอ็นต์ที่ได้จากคอนโซล API |
grant_type |
ตามที่กำหนดไว้ในข้อกำหนด OAuth 2.0 ค่าของช่องนี้ต้องตั้งค่าเป็น refresh_token |
refresh_token |
โทเค็นการรีเฟรชที่แสดงผลจากการแลกเปลี่ยนรหัสการให้สิทธิ์ |
แม้ว่าการใช้ DPoP จะเป็นตัวเลือก แต่เราขอแนะนำให้ใช้เพื่อเพิ่มความปลอดภัย หากต้องการใช้ DPoP กับโทเค็นการรีเฟรช แอปพลิเคชันของคุณต้องสร้าง JWT หลักฐาน DPoP ใหม่ที่ไม่ซ้ำกันสำหรับคำขอแต่ละรายการไปยังปลายทางโทเค็น หลักฐานนี้ต้องลงนามด้วยคีย์ส่วนตัวเดียวกันกับที่ใช้ระหว่างการแลกเปลี่ยนรหัสการให้สิทธิ์ครั้งแรก แอปพลิเคชันจะเพิ่มหลักฐานเป็นส่วนหัวของคำขอ HTTP
| ส่วนหัว | ต้องระบุ | คำอธิบาย |
|---|---|---|
DPoP |
ไม่บังคับ | หลักฐาน DPoP คือ JWT ที่พิสูจน์การครอบครองคีย์ส่วนตัว นี่คือส่วนหัว ไม่ใช่พารามิเตอร์ หากระบุไว้ โทเค็นที่แสดงผลจะเชื่อมโยงกับคีย์นี้ ต้องสร้างหลักฐานใหม่ที่ไม่ซ้ำกันสำหรับคำขอแต่ละรายการ และต้องรวมการอ้างสิทธิ์ htm (เมธอด HTTP) และ htu (HTTP URI) ที่ตรงกับคำขอ |
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างคำขอ
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded DPoP: DPOP_PROOF_JWT client_id=your_client_id& refresh_token=refresh_token& grant_type=refresh_token
หากต้องการใช้ DPoP กับโทเค็นการรีเฟรช คุณต้องสร้าง JWT หลักฐาน DPoP ใหม่ที่ไม่ซ้ำกันสำหรับคำขอ ดูสร้างการพิสูจน์ DPoP สำหรับวิธีการทีละขั้นตอนในการสร้างคู่คีย์และสร้าง JWT
การแลกเปลี่ยนที่สำเร็จจะแสดงด้วยการตอบกลับ 200 OK ที่มีโทเค็นเพื่อการเข้าถึงใหม่ เมื่อใช้ DPoP token_type จะเป็น Bearer การตอบกลับที่สำเร็จจะยืนยันว่าระบบยอมรับการพิสูจน์ DPoP สำหรับโทเค็นการรีเฟรช นอกจากนี้ Google อาจแสดงส่วนหัว HTTP DPoP-Nonce ใหม่ในการตอบกลับด้วย หากแสดง ไคลเอ็นต์ของคุณต้องแคช Nonce นี้และรวมไว้ในการอ้างสิทธิ์ nonce ของหลักฐาน DPoP ในคำขอต่อๆ ไป
การแลกเปลี่ยนที่ล้มเหลวจะเกิดขึ้นหากส่วนหัว DPoP ขาดหายไป ไม่ถูกต้อง หรือใช้คีย์ที่ไม่ถูกต้อง ดูรายละเอียดเกี่ยวกับรหัสข้อผิดพลาด DPoP ที่เฉพาะเจาะจงและการจัดการ Nonce ได้ที่การแลกเปลี่ยนไม่สำเร็จ
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างส่วนหัวการตอบกลับและเนื้อหาที่สำเร็จเมื่อใช้ DPoP
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly",
"token_type": "Bearer"
}โปรดทราบว่ามีการจำกัดจำนวนโทเค็นการรีเฟรชที่จะออก โดยจำกัด 1 รายการต่อชุดค่าผสมไคลเอ็นต์/ผู้ใช้ และอีก 1 รายการต่อผู้ใช้ในไคลเอ็นต์ทั้งหมด คุณควรบันทึกโทเค็นการรีเฟรชไว้ในพื้นที่เก็บข้อมูลระยะยาวและใช้ต่อไปตราบใดที่โทเค็นยังคงใช้ได้ หากแอปพลิเคชันของคุณขอโทเค็นการรีเฟรชมากเกินไป อาจทำให้เกินขีดจำกัดเหล่านี้ ซึ่งในกรณีนี้โทเค็นการรีเฟรชที่เก่ากว่าจะหยุดทำงาน
การเพิกถอนโทเค็น
ในบางกรณี ผู้ใช้อาจต้องการเพิกถอนสิทธิ์เข้าถึงที่ให้ไว้กับแอปพลิเคชัน ผู้ใช้สามารถเพิกถอนสิทธิ์เข้าถึงได้โดยไปที่ การตั้งค่าบัญชี ดูข้อมูลเพิ่มเติมได้ในเอกสารสนับสนุนเรื่องนำสิทธิ์เข้าถึงเว็บไซต์หรือแอปออกในส่วนเว็บไซต์และแอปของบุคคลที่สามที่มีสิทธิ์เข้าถึงบัญชีของคุณ
นอกจากนี้ แอปพลิเคชันยังเพิกถอนสิทธิ์เข้าถึงที่ได้รับโดยใช้โปรแกรมได้ด้วย การเพิกถอนแบบเป็นโปรแกรมมีความสำคัญในกรณีที่ผู้ใช้ยกเลิกการสมัครใช้บริการ นำแอปพลิเคชันออก หรือทรัพยากร API ที่แอปต้องใช้มีการเปลี่ยนแปลงอย่างมาก กล่าวคือ ส่วนหนึ่งของกระบวนการนำออกอาจรวมถึงคำขอ API เพื่อให้แน่ใจว่าสิทธิ์ที่ให้ไว้กับแอปพลิเคชันก่อนหน้านี้ถูกนำออกแล้ว
PHP
หากต้องการเพิกถอนโทเค็นแบบเป็นโปรแกรม ให้เรียกใช้ revokeToken() ดังนี้
$client->revokeToken();Python
หากต้องการเพิกถอนโทเค็นแบบเป็นโปรแกรม ให้ส่งคำขอไปยัง https://oauth2.googleapis.com/revoke ที่มีโทเค็นเป็นพารามิเตอร์และตั้งค่าส่วนหัว Content-Type ดังนี้
requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'})
Ruby
หากต้องการเพิกถอนโทเค็นแบบเป็นโปรแกรม ให้ส่งคำขอ HTTP ไปยังปลายทาง oauth2.revoke ดังนี้
uri = URI('https://oauth2.googleapis.com/revoke') response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
โทเค็นอาจเป็นโทเค็นเพื่อการเข้าถึงหรือโทเค็นการรีเฟรชก็ได้ หากโทเค็นเป็นโทเค็นเพื่อการเข้าถึงและมีโทเค็นการรีเฟรชที่เกี่ยวข้อง ระบบจะเพิกถอนโทเค็นการรีเฟรชด้วย
หากการเพิกถอนได้รับการประมวลผลเรียบร้อยแล้ว รหัสสถานะของการตอบกลับจะเป็น 200 สำหรับเงื่อนไขข้อผิดพลาด ระบบจะแสดงรหัสสถานะ 400 พร้อมกับรหัสข้อผิดพลาด
Node.js
หากต้องการเพิกถอนโทเค็นแบบเป็นโปรแกรม ให้ส่งคำขอ HTTPS POST ไปยังปลายทาง /revoke ดังนี้
const https = require('https'); // Build the string for the POST request let postData = "token=" + userCredential.access_token; // Options for POST request to Google's OAuth 2.0 server to revoke a token let postOptions = { host: 'oauth2.googleapis.com', port: '443', path: '/revoke', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; // Set up the request const postReq = https.request(postOptions, function (res) { res.setEncoding('utf8'); res.on('data', d => { console.log('Response: ' + d); }); }); postReq.on('error', error => { console.log(error) }); // Post the request with data postReq.write(postData); postReq.end();
พารามิเตอร์โทเค็นอาจเป็นโทเค็นเพื่อการเข้าถึงหรือโทเค็นการรีเฟรชก็ได้ หากโทเค็นเป็นโทเค็นเพื่อการเข้าถึงและมีโทเค็นการรีเฟรชที่เกี่ยวข้อง ระบบจะเพิกถอนโทเค็นการรีเฟรชด้วย
หากการเพิกถอนได้รับการประมวลผลเรียบร้อยแล้ว รหัสสถานะของการตอบกลับจะเป็น 200 สำหรับเงื่อนไขข้อผิดพลาด ระบบจะแสดงรหัสสถานะ 400 พร้อมกับรหัสข้อผิดพลาด
HTTP/REST
หากต้องการเพิกถอนโทเค็นแบบเป็นโปรแกรม แอปพลิเคชันของคุณจะส่งคำขอไปยัง https://oauth2.googleapis.com/revoke และรวมโทเค็นเป็นพารามิเตอร์ ดังนี้
curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
https://oauth2.googleapis.com/revoke?token={token}โทเค็นอาจเป็นโทเค็นเพื่อการเข้าถึงหรือโทเค็นการรีเฟรชก็ได้ หากโทเค็นเป็นโทเค็นเพื่อการเข้าถึงและมีโทเค็นการรีเฟรชที่เกี่ยวข้อง ระบบจะเพิกถอนโทเค็นการรีเฟรชด้วย
หากการเพิกถอนได้รับการประมวลผลเรียบร้อยแล้ว รหัสสถานะ HTTP ของการตอบกลับจะเป็น 200 สำหรับเงื่อนไขข้อผิดพลาด ระบบจะแสดงรหัสสถานะ HTTP 400 พร้อมกับรหัสข้อผิดพลาด
การเข้าถึงตามเวลา
สิทธิ์เข้าถึงตามเวลาช่วยให้ผู้ใช้ให้สิทธิ์แอปเข้าถึงข้อมูลของตนเป็นระยะเวลาจำกัดเพื่อดำเนินการให้เสร็จสมบูรณ์ การเข้าถึงตามเวลาพร้อมใช้งานในผลิตภัณฑ์บางอย่างของ Google ในระหว่างขั้นตอนขอความยินยอม ซึ่งจะให้ตัวเลือกแก่ผู้ใช้ในการให้สิทธิ์เข้าถึงเป็นระยะเวลาที่จำกัด ตัวอย่างเช่น Data Portability API ซึ่งช่วยให้โอนข้อมูลได้แบบครั้งเดียว
เมื่อผู้ใช้ให้สิทธิ์เข้าถึงตามเวลาแก่แอปพลิเคชันของคุณ โทเค็นการรีเฟรชจะหมดอายุหลังจากระยะเวลาที่ระบุ โปรดทราบว่าโทเค็นการรีเฟรชอาจใช้งานไม่ได้ก่อนหน้านี้ในบางสถานการณ์ โปรดดูรายละเอียดในกรณีเหล่านี้ ฟิลด์ refresh_token_expires_in ที่แสดงในการตอบกลับการแลกเปลี่ยนรหัสการให้สิทธิ์แสดงถึงเวลาที่เหลือจนกว่าโทเค็นการรีเฟรชจะหมดอายุในกรณีดังกล่าว
ใช้การป้องกันแบบครอบคลุมหลายบริการ
ขั้นตอนเพิ่มเติมที่คุณควรทำเพื่อปกป้องบัญชีของผู้ใช้คือการใช้การป้องกันแบบครอบคลุมหลายบริการโดยใช้บริการการป้องกันแบบครอบคลุมหลายบริการของ Google บริการนี้ช่วยให้คุณสมัครรับการแจ้งเตือนการดำเนินการด้านความปลอดภัยซึ่งให้ข้อมูลแก่แอปพลิเคชันเกี่ยวกับการเปลี่ยนแปลงที่สำคัญในบัญชีผู้ใช้ จากนั้น คุณสามารถใช้ข้อมูลดังกล่าวเพื่อดำเนินการตามวิธีที่คุณตัดสินใจตอบสนองต่อเหตุการณ์
ตัวอย่างประเภทเหตุการณ์ที่บริการการป้องกันแบบครอบคลุมหลายบริการของ Google ส่งไปยังแอปของคุณมีดังนี้
-
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked -
https://schemas.openid.net/secevent/oauth/event-type/token-revoked -
https://schemas.openid.net/secevent/risc/event-type/account-disabled
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้การป้องกันแบบครอบคลุมหลายบริการและรายการเหตุการณ์ทั้งหมดที่พร้อมใช้งานได้ที่หน้า ปกป้องบัญชีผู้ใช้ด้วยการป้องกันแบบครอบคลุมหลายบริการ