เอกสารนี้อธิบายวิธีที่แอปพลิเคชันเว็บเซิร์ฟเวอร์ใช้ไลบรารีของไคลเอ็นต์ Google API หรือปลายทาง OAuth 2.0 ของ Google เพื่อใช้การให้สิทธิ์ 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 ที่ต้องการเปิดใช้ในรายการ ให้ใช้การค้นหาเพื่อค้นหา หรือคลิกดูทั้งหมดในตระกูลผลิตภัณฑ์ของ API นั้น
- เลือก API ที่ต้องการเปิดใช้ แล้วคลิกปุ่มเปิดใช้
สร้างข้อมูลเข้าสู่ระบบการให้สิทธิ์
แอปพลิเคชันที่ใช้ OAuth 2.0 เพื่อเข้าถึง Google APIs ต้องมีข้อมูลเข้าสู่ระบบการให้สิทธิ์ที่ระบุแอปพลิเคชันนั้นแก่เซิร์ฟเวอร์ OAuth 2.0 ของ Google ขั้นตอนต่อไปนี้จะอธิบายวิธีสร้างข้อมูลเข้าสู่ระบบสำหรับโปรเจ็กต์ จากนั้นแอปพลิเคชันจะใช้ข้อมูลเข้าสู่ระบบดังกล่าวเพื่อเข้าถึง API ที่คุณเปิดใช้สำหรับโปรเจ็กต์นั้นได้
- คลิกสร้างข้อมูลเข้าสู่ระบบ > รหัสไคลเอ็นต์ OAuth
- เลือกประเภทแอปพลิเคชันเว็บแอปพลิเคชัน
- กรอกแบบฟอร์มแล้วคลิกสร้าง แอปพลิเคชันที่ใช้ภาษาและเฟรมเวิร์กต่างๆ เช่น PHP, Java, Python, Ruby และ .NET จะต้องระบุ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาต URI เปลี่ยนเส้นทางคือปลายทางที่เซิร์ฟเวอร์ OAuth 2.0 สามารถส่งการตอบกลับได้ โดยปลายทางเหล่านี้ต้องเป็นไปตามกฎการตรวจสอบของ Google
สำหรับการทดสอบ คุณสามารถระบุ URI ที่อ้างอิงถึงเครื่องในเครื่อง เช่น
http://localhost:8080
โปรดทราบว่าตัวอย่างทั้งหมดในเอกสารนี้ใช้http://localhost:8080
เป็น URI การเปลี่ยนเส้นทางเราขอแนะนําให้คุณออกแบบปลายทางการตรวจสอบสิทธิ์ของแอปเพื่อให้แอปพลิเคชันไม่แสดงโค้ดการให้สิทธิ์แก่ทรัพยากรอื่นๆ ในหน้า
หลังจากสร้างข้อมูลเข้าสู่ระบบแล้ว ให้ดาวน์โหลดไฟล์ client_secret.json จาก เก็บไฟล์อย่างปลอดภัยในตำแหน่งที่มีเพียงแอปพลิเคชันของคุณเท่านั้นที่เข้าถึงได้
ระบุขอบเขตการเข้าถึง
ขอบเขตช่วยให้แอปพลิเคชันขอสิทธิ์เข้าถึงเฉพาะทรัพยากรที่จําเป็นเท่านั้น และช่วยให้ผู้ใช้ควบคุมระดับการเข้าถึงที่มอบให้กับแอปพลิเคชันได้ด้วย ดังนั้น จำนวนขอบเขตที่ขอจึงอาจสัมพันธ์กับแนวโน้มที่จะได้รับความยินยอมจากผู้ใช้ในลักษณะผกผัน
ก่อนเริ่มใช้การให้สิทธิ์ OAuth 2.0 เราขอแนะนำให้คุณระบุขอบเขตที่แอปจะต้องได้รับสิทธิ์เข้าถึง
นอกจากนี้ เราขอแนะนำให้แอปพลิเคชันขอสิทธิ์เข้าถึงขอบเขตการให้สิทธิ์ผ่านกระบวนการการให้สิทธิ์ทีละส่วน ซึ่งแอปพลิเคชันจะขอสิทธิ์เข้าถึงข้อมูลผู้ใช้ตามบริบท แนวทางปฏิบัติแนะนำนี้ช่วยให้ผู้ใช้เข้าใจได้ง่ายขึ้นว่าเหตุใดแอปพลิเคชันจึงต้องการสิทธิ์เข้าถึงที่ขอ
เอกสารขอบเขต OAuth 2.0 API มีรายการขอบเขตทั้งหมดที่คุณอาจใช้เพื่อเข้าถึง Google API
ข้อกำหนดเฉพาะภาษา
หากต้องการเรียกใช้ตัวอย่างโค้ดในเอกสารนี้ คุณจะต้องมีบัญชี Google, สิทธิ์เข้าถึงอินเทอร์เน็ต และเว็บเบราว์เซอร์ หากคุณใช้ไลบรารีไคลเอ็นต์ API รายการใดรายการหนึ่ง โปรดดูข้อกําหนดเฉพาะภาษาด้านล่างด้วย
PHP
หากต้องการเรียกใช้ตัวอย่างโค้ด PHP ในเอกสารนี้ คุณจะต้องมีสิ่งต่อไปนี้
- PHP 8.0 ขึ้นไปที่ติดตั้งอินเทอร์เฟซบรรทัดคำสั่ง (CLI) และส่วนขยาย JSON
- เครื่องมือการจัดการทรัพยากรของ 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 ของ
requests
pip install --upgrade requests
โปรดอ่านหมายเหตุเกี่ยวกับรุ่นของไลบรารีของไคลเอ็นต์ Google API สำหรับ Python หากอัปเกรด Python และคู่มือการย้ายข้อมูลที่เกี่ยวข้องไม่ได้
Ruby
หากต้องการเรียกใช้ตัวอย่างโค้ด Ruby ในเอกสารนี้ คุณจะต้องมีสิ่งต่อไปนี้
- Ruby 2.6 ขึ้นไป
-
ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Ruby
gem install googleauth
-
ไลบรารีของไคลเอ็นต์สำหรับ Google API ของไดรฟ์และปฏิทิน
gem install google-apis-drive_v3 google-apis-calendar_v3
-
เฟรมเวิร์กเว็บแอปพลิเคชัน Ruby ของ Sinatra
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 คุณจะต้องสร้างและกำหนดค่าออบเจ็กต์ที่กำหนดพารามิเตอร์เหล่านี้
- หากเรียกใช้ปลายทาง OAuth 2.0 ของ Google โดยตรง คุณจะต้องสร้าง 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 |
จำเป็น
รหัสไคลเอ็นต์สําหรับแอปพลิเคชัน คุณดูค่านี้ได้ในส่วน |
||||||
redirect_uri |
จำเป็น
กำหนดตำแหน่งที่เซิร์ฟเวอร์ API จะเปลี่ยนเส้นทางผู้ใช้หลังจากที่ผู้ใช้ทำตามขั้นตอนการให้สิทธิ์จนเสร็จสมบูรณ์ ค่าต้องตรงกับ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตรายการใดรายการหนึ่งสำหรับไคลเอ็นต์ OAuth 2.0 ที่คุณกำหนดค่าไว้ใน
ของลูกค้า หากค่านี้ไม่ตรงกับ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตสําหรับ โปรดทราบว่ารูปแบบ |
||||||
response_type |
จำเป็น
กำหนดว่าปลายทาง OAuth 2.0 ของ Google จะแสดงผลรหัสการให้สิทธิ์หรือไม่ ตั้งค่าพารามิเตอร์เป็น |
||||||
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
ที่สร้างขึ้นจากขั้นตอนที่ 1generateAuthUrl
เพื่อขอสิทธิ์เข้าถึงจากเซิร์ฟเวอร์ OAuth 2.0 ของ Google -
เปลี่ยนเส้นทางผู้ใช้ไปยัง
authorizationUrl
res.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//oauth2.example.com/code& 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 โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ผู้ดูแลระบบอาจจํากัดการเข้าถึงขอบเขตทั้งหมดหรือขอบเขตที่มีความละเอียดอ่อนและถูกจํากัดจนกว่าจะมีการให้สิทธิ์เข้าถึงรหัสไคลเอ็นต์ OAuth ของคุณอย่างชัดเจนในบทความความช่วยเหลือสําหรับผู้ดูแลระบบ Google Workspace ที่หัวข้อ ควบคุมว่าจะให้แอปของบุคคลที่สามและแอปภายในรายการใดเข้าถึงข้อมูล Google Workspace ได้บ้าง
disallowed_useragent
ปลายทางการให้สิทธิ์จะแสดงภายใน User Agent ที่ฝังซึ่งนโยบาย OAuth 2.0 ของ Google ไม่อนุญาต
Android
นักพัฒนาแอป Android อาจเห็นข้อความแสดงข้อผิดพลาดนี้เมื่อเปิดคําขอการให้สิทธิ์ใน android.webkit.WebView
นักพัฒนาแอปควรใช้ไลบรารี Android เช่น Google Sign-In สำหรับ Android หรือ AppAuth สำหรับ Android ของ OpenID Foundation แทน
นักพัฒนาเว็บอาจพบข้อผิดพลาดนี้เมื่อแอป Android เปิดลิงก์เว็บทั่วไปใน User Agent ที่ฝังอยู่ และผู้ใช้ไปยังปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google จากเว็บไซต์ของคุณ นักพัฒนาแอปควรอนุญาตให้ลิงก์ทั่วไปเปิดในตัวแฮนเดิลลิงก์เริ่มต้นของระบบปฏิบัติการ ซึ่งรวมถึงตัวแฮนเดิล App Link ของ Android หรือแอปเบราว์เซอร์เริ่มต้น นอกจากนี้ ระบบยังรองรับตัวเลือกไลบรารี Android Custom Tabs ด้วย
iOS
นักพัฒนาแอป 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 รวมถึงรหัสไคลเอ็นต์และรหัสลับที่ใช้สำหรับคำขอนี้
invalid_grant
เมื่อรีเฟรชโทเค็นการเข้าถึงหรือใช้การให้สิทธิ์เพิ่มเติม โทเค็นอาจหมดอายุหรือไม่ถูกต้อง ตรวจสอบสิทธิ์ผู้ใช้อีกครั้งและขอความยินยอมจากผู้ใช้เพื่อรับโทเค็นใหม่ หากยังเห็นข้อผิดพลาดนี้อยู่ ให้ตรวจสอบว่าได้กําหนดค่าแอปพลิเคชันอย่างถูกต้องและใช้โทเค็นและพารามิเตอร์ที่ถูกต้องในคําขอ มิฉะนั้น บัญชีผู้ใช้อาจถูกลบหรือปิดใช้
redirect_uri_mismatch
redirect_uri
ที่ส่งในคําขอการให้สิทธิ์ไม่ตรงกับ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตสําหรับรหัสไคลเอ็นต์ OAuth ตรวจสอบ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตใน
พารามิเตอร์ redirect_uri
อาจหมายถึงขั้นตอนการส่งผ่านข้อมูลนอกแบนด์ (OOB) ของ OAuth ซึ่งเลิกใช้งานแล้วและไม่รองรับอีกต่อไป โปรดดูคู่มือการย้ายข้อมูลเพื่ออัปเดตการผสานรวม
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//oauth2.example.com/code& client_id=client_id
หลังจากทำตามขั้นตอน OAuth 2.0 จนเสร็จสมบูรณ์แล้ว ระบบจะเปลี่ยนเส้นทางคุณไปที่ http://localhost/oauth2callback
ซึ่งอาจแสดงข้อผิดพลาด 404 NOT FOUND
เว้นแต่เครื่องคอมพิวเตอร์ของคุณจะแสดงไฟล์ที่อยู่ที่ดังกล่าว ขั้นตอนถัดไปจะแสดงรายละเอียดเพิ่มเติมเกี่ยวกับข้อมูลที่แสดงใน URI เมื่อระบบเปลี่ยนเส้นทางผู้ใช้กลับไปที่แอปพลิเคชัน
ขั้นตอนที่ 5: เปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นรีเฟรชและโทเค็นการเข้าถึง
หลังจากเว็บเซิร์ฟเวอร์ได้รับรหัสการให้สิทธิ์แล้ว ก็จะแลกเปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นการเข้าถึงได้
PHP
หากต้องการเปลี่ยนรหัสการให้สิทธิ์เป็นโทเค็นการเข้าถึง ให้ใช้วิธี fetchAccessTokenWithAuthCode
ดังนี้
$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
Python
ในหน้าการเรียกกลับ ให้ใช้ไลบรารี 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 the session. # ACTION ITEM for developers: # Store user's access and refresh tokens in your data store if # incorporating this code into your real app. credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, 'granted_scopes': credentials.granted_scopes}
Ruby
ในหน้าการเรียกกลับ ให้ใช้ไลบรารี 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 |
รหัสไคลเอ็นต์ที่ได้รับจาก |
client_secret |
รหัสลับไคลเอ็นต์ที่ได้รับจาก |
code |
รหัสการให้สิทธิ์ที่แสดงผลจากคำขอเริ่มต้น |
grant_type |
ตามที่กำหนดไว้ในข้อกำหนด OAuth 2.0 ค่าของช่องนี้ต้องตั้งเป็น authorization_code |
redirect_uri |
URI การเปลี่ยนเส้นทางรายการใดรายการหนึ่งสำหรับโปรเจ็กต์ของคุณใน
สําหรับ
client_id |
ข้อมูลโค้ดต่อไปนี้แสดงคำขอตัวอย่าง
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7& client_id=your_client_id& client_secret=your_client_secret& redirect_uri=https%3A//oauth2.example.com/code& grant_type=authorization_code
Google จะตอบกลับคําขอนี้โดยการส่งคืนออบเจ็กต์ JSON ที่มีโทเค็นการเข้าถึงที่มีอายุสั้นและโทเค็นการรีเฟรช
โปรดทราบว่าระบบจะแสดงโทเค็นรีเฟรชก็ต่อเมื่อแอปพลิเคชันของคุณตั้งค่าพารามิเตอร์ access_type
เป็น offline
ในคำขอเริ่มต้นไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google
การตอบกลับจะมีฟิลด์ต่อไปนี้
ช่อง | |
---|---|
access_token |
โทเค็นที่แอปพลิเคชันส่งเพื่อให้สิทธิ์คําขอ Google API |
expires_in |
อายุการใช้งานที่เหลือของโทเค็นการเข้าถึงเป็นวินาที |
refresh_token |
โทเค็นที่คุณสามารถใช้รับโทเค็นการเข้าถึงใหม่ โทเค็นรีเฟรชจะใช้ได้จนกว่าผู้ใช้จะเพิกถอนสิทธิ์เข้าถึง
โปรดทราบว่าช่องนี้จะปรากฏในการตอบกลับนี้เฉพาะในกรณีที่คุณตั้งค่าพารามิเตอร์ access_type เป็น offline ในคำขอเริ่มต้นไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google
|
scope |
ขอบเขตการเข้าถึงที่ access_token มอบให้ซึ่งแสดงเป็นรายการสตริงที่เว้นวรรคคั่นและคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ |
token_type |
ประเภทของโทเค็นที่แสดงผล ขณะนี้ ค่าของช่องนี้จะตั้งไว้เป็น Bearer เสมอ |
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างคำตอบ
{ "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: ตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์
เมื่อขอขอบเขตหลายรายการพร้อมกัน ผู้ใช้อาจไม่ให้สิทธิ์ขอบเขตทั้งหมดที่แอปขอ แอปของคุณควรตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์ไว้เสมอ และจัดการกับการปฏิเสธขอบเขตด้วยการปิดใช้ฟีเจอร์ที่เกี่ยวข้อง ดูข้อมูลเพิ่มเติมที่วิธีจัดการสิทธิ์แบบละเอียด
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, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, '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
ในการตอบกลับโทเค็นการเข้าถึง ขอบเขตการเข้าถึงที่ granted โดย access_token ที่แสดงเป็นรายการสตริงที่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่และเว้นวรรคคั่น
ตัวอย่างเช่น ตัวอย่างการตอบกลับโทเค็นการเข้าถึงต่อไปนี้บ่งชี้ว่าผู้ใช้ได้ให้สิทธิ์เข้าถึงกิจกรรมในไดรฟ์และกิจกรรมในปฏิทินแบบอ่านอย่างเดียวแก่แอปพลิเคชันของคุณ
{ "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 API โดยทําตามขั้นตอนต่อไปนี้
- หากต้องการใช้โทเค็นการเข้าถึงกับออบเจ็กต์
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 Authorization
Bearer
หากเป็นไปได้ เราขอแนะนำให้ใช้ส่วนหัว HTTP เนื่องจากสตริงการค้นหามีแนวโน้มที่จะปรากฏในบันทึกของเซิร์ฟเวอร์ ในกรณีส่วนใหญ่ คุณสามารถใช้ไลบรารีของไคลเอ็นต์เพื่อตั้งค่าการเรียกใช้ Google API (เช่น เมื่อเรียกใช้ Drive Files API)
คุณสามารถลองใช้ Google API ทั้งหมดและดูขอบเขตของ API เหล่านั้นได้ที่ 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
ตัวอย่างที่สมบูรณ์
ตัวอย่างต่อไปนี้จะแสดงรายการไฟล์ในรูปแบบ JSON ใน Google ไดรฟ์ของผู้ใช้หลังจากที่ผู้ใช้ตรวจสอบสิทธิ์และให้ความยินยอมแก่แอปพลิเคชันในการเข้าถึงข้อมูลเมตาของไดรฟ์
PHP
วิธีเรียกใช้ตัวอย่างนี้
- ใน ให้เพิ่ม 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
- หน้าจำลองเพื่อเรียกใช้ปฏิทิน API: ลิงก์นี้จะไปยังหน้าจำลองที่พยายามเรียกใช้คำขอตัวอย่างปฏิทิน API หากผู้ใช้ให้สิทธิ์ และเริ่มขั้นตอนการให้สิทธิ์หากจําเป็น หากสําเร็จ หน้าเว็บจะแสดงการตอบกลับของ API
- ทดสอบขั้นตอนการให้สิทธิ์โดยตรง: ลิงก์นี้จะไปยังหน้าที่พยายามส่งผู้ใช้ผ่านขั้นตอนการให้สิทธิ์ แอปขอสิทธิ์ในการส่งคําขอ API ที่ได้รับอนุญาตในนามของผู้ใช้
- เพิกถอนข้อมูลเข้าสู่ระบบปัจจุบัน: ลิงก์นี้จะไปยังหน้าที่ เพิกถอนสิทธิ์ที่ผู้ใช้ให้ไว้กับแอปพลิเคชันแล้ว
- ล้างข้อมูลเข้าสู่ระบบเซสชัน Flask: ลิงก์นี้จะล้างข้อมูลเข้าสู่ระบบการให้สิทธิ์ที่จัดเก็บไว้ในเซสชัน Flask ซึ่งจะช่วยให้คุณเห็นว่าจะเกิดอะไรขึ้นหากผู้ใช้ที่เคยให้สิทธิ์แก่แอปของคุณพยายามเรียกใช้คําขอ API ในเซสชันใหม่ นอกจากนี้ คุณยังดูการตอบกลับของ API ที่แอปจะได้รับได้หากผู้ใช้เพิกถอนสิทธิ์ที่มอบให้แอป และแอปยังคงพยายามให้สิทธิ์คําขอด้วยโทเค็นการเข้าถึงที่ถูกเพิกถอน
# -*- coding: utf-8 -*- import os import flask 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 credentials from the session. credentials = google.oauth2.credentials.Credentials( **flask.session['credentials']) 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. # ACTION ITEM: In a production app, you likely want to save these # credentials in a persistent database instead. flask.session['credentials'] = credentials_to_dict(credentials) return flask.jsonify(**files) else: # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly 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.') credentials = google.oauth2.credentials.Credentials( **flask.session['credentials']) 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: 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, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, '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="/test">Test an API request</a></td>' + '<td>Submit an API request and see a formatted JSON response. ' + ' Go through the authorization flow if there are no stored ' + ' credentials for the user.</td></tr>' + '<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="/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="/test">test the ' + ' API request</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 . 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
วิธีเรียกใช้ตัวอย่างนี้
-
ใน ให้เพิ่ม URL ของเครื่องที่ใช้งานอยู่ลงในรายการ URL การเปลี่ยนเส้นทาง เช่น เพิ่ม
http://localhost
- ตรวจสอบว่าคุณได้ติดตั้ง LTS เวอร์ชันปัจจุบัน, 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 การเปลี่ยนเส้นทางต้องเป็นไปตามกฎเหล่านี้ ดูคำจำกัดความของโดเมน โฮสต์ เส้นทาง การค้นหา สคีมา และ userinfo ที่กล่าวถึงด้านล่างได้จาก RFC 3986 ส่วนที่ 3
กฎการตรวจสอบความถูกต้อง | |
---|---|
รูปแบบ |
URI การเปลี่ยนเส้นทางต้องใช้รูปแบบ HTTPS ไม่ใช่ HTTP ธรรมดา URI ของ localhost (รวมถึง URI ที่อยู่ IP ของ localhost) จะได้รับการยกเว้นจากกฎนี้ |
โฮสต์ |
โฮสต์ต้องไม่ใช่ที่อยู่ IP ดิบ ที่อยู่ IP ของ localhost ได้รับการยกเว้นจากกฎนี้ |
โดเมน |
“googleusercontent.com” goo.gl ) เว้นแต่แอปจะเป็นเจ้าของโดเมนนั้น นอกจากนี้ หากแอปที่เป็นเจ้าของโดเมนตัวย่อเลือกที่จะเปลี่ยนเส้นทางไปยังโดเมนนั้น URI การเปลี่ยนเส้นทางดังกล่าวต้องมี“/google-callback/” ในเส้นทางหรือลงท้ายด้วย“/google-callback” |
Userinfo |
URI การเปลี่ยนเส้นทางต้องไม่มีคอมโพเนนต์ย่อย userinfo |
เส้นทาง |
URI การเปลี่ยนเส้นทางต้องไม่มี Path Traversal (หรือที่เรียกว่าการย้อนกลับไดเรกทอรี) ซึ่งแสดงด้วย |
การค้นหา |
URI การเปลี่ยนเส้นทางต้องไม่มีการเปลี่ยนเส้นทางแบบเปิด |
เศษข้อความ |
URI การเปลี่ยนเส้นทางต้องไม่มีคอมโพเนนต์ของ URL ย่อย |
อักขระ |
URI การเปลี่ยนเส้นทางต้องไม่มีอักขระบางตัว ดังนี้
|
การให้สิทธิ์เพิ่มเติม
ในโปรโตคอล OAuth 2.0 แอปจะขอสิทธิ์เข้าถึงทรัพยากร ซึ่งระบุด้วยขอบเขต การขอสิทธิ์เข้าถึงทรัพยากรเมื่อต้องการถือเป็นแนวทางปฏิบัติแนะนําด้านประสบการณ์ของผู้ใช้ เซิร์ฟเวอร์การให้สิทธิ์ของ Google รองรับการให้สิทธิ์แบบเพิ่มทีละรายการเพื่อเปิดใช้แนวทางปฏิบัติดังกล่าว ฟีเจอร์นี้ช่วยให้คุณขอขอบเขตได้ตามต้องการ และหากผู้ใช้ให้สิทธิ์สําหรับขอบเขตใหม่ ระบบจะแสดงรหัสการให้สิทธิ์ซึ่งอาจแลกเป็นโทเค็นที่มีขอบเขตทั้งหมดที่ผู้ใช้ให้สิทธิ์โปรเจ็กต์
ตัวอย่างเช่น แอปที่อนุญาตให้ผู้ใช้ลองฟังแทร็กเพลงและสร้างมิกซ์อาจต้องใช้ทรัพยากรเพียงเล็กน้อยเมื่อลงชื่อเข้าใช้ อาจเป็นแค่ชื่อของผู้ลงชื่อเข้าใช้ อย่างไรก็ตาม การบันทึกมิกซ์ที่เสร็จสมบูรณ์จะต้องเข้าถึง Google ไดรฟ์ของบุคคลนั้น ผู้ใช้ส่วนใหญ่จะรู้สึกเป็นธรรมชาติหากมีการขอสิทธิ์เข้าถึง Google ไดรฟ์เฉพาะตอนที่แอปต้องการจริงๆ
ในกรณีนี้ ณ เวลาลงชื่อเข้าใช้ แอปอาจขอขอบเขต openid
และ profile
เพื่อลงชื่อเข้าใช้ขั้นพื้นฐาน จากนั้นจึงขอขอบเขต https://www.googleapis.com/auth/drive.file
ในภายหลัง ณ เวลาของคำขอแรกเพื่อบันทึกมิกซ์
หากต้องการใช้การให้สิทธิ์แบบเพิ่ม ให้ทำตามขั้นตอนปกติในการขอโทเค็นการเข้าถึง แต่ตรวจสอบว่าคำขอการให้สิทธิ์มีขอบเขตที่ได้รับอนุญาตก่อนหน้านี้ แนวทางนี้ช่วยให้แอปไม่ต้องจัดการโทเค็นการเข้าถึงหลายรายการ
กฎต่อไปนี้จะมีผลกับโทเค็นการเข้าถึงที่ได้รับจากการให้สิทธิ์เพิ่มเติม
- โทเค็นนี้สามารถใช้เพื่อเข้าถึงทรัพยากรที่เกี่ยวข้องกับขอบเขตใดก็ได้ที่รวมอยู่ในการให้สิทธิ์แบบรวมใหม่
- เมื่อคุณใช้โทเค็นการรีเฟรชสำหรับการให้สิทธิ์แบบรวมเพื่อให้ได้โทเค็นการเข้าถึง โทเค็นการเข้าถึงจะแสดงถึงการให้สิทธิ์แบบรวมและสามารถใช้กับค่า
scope
ใดก็ได้ที่รวมอยู่ในการตอบกลับ - การให้สิทธิ์แบบรวมจะมีขอบเขตทั้งหมดที่ผู้ใช้ให้สิทธิ์แก่โปรเจ็กต์ API แม้ว่าจะมีการขอสิทธิ์จากลูกค้ารายอื่นก็ตาม เช่น หากผู้ใช้ให้สิทธิ์เข้าถึงขอบเขตหนึ่งโดยใช้ไคลเอ็นต์เดสก์ท็อปของแอปพลิเคชัน แล้วให้สิทธิ์อีกขอบเขตหนึ่งแก่แอปพลิเคชันเดียวกันผ่านไคลเอ็นต์อุปกรณ์เคลื่อนที่ การอนุญาตแบบรวมจะมีทั้ง 2 ขอบเขต
- หากคุณเพิกถอนโทเค็นที่แสดงถึงการให้สิทธิ์แบบรวม ระบบจะเพิกถอนสิทธิ์เข้าถึงขอบเขตทั้งหมดของการให้สิทธิ์นั้นในนามของผู้ใช้ที่เชื่อมโยงพร้อมกัน
ตัวอย่างโค้ดเฉพาะภาษาในขั้นตอนที่ 1: ตั้งค่าพารามิเตอร์การให้สิทธิ์และตัวอย่าง URL การเปลี่ยนเส้นทาง HTTP/REST ในขั้นตอนที่ 2: เปลี่ยนเส้นทางไปยังเซิร์ฟเวอร์ 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//oauth2.example.com/code& prompt=consent& include_granted_scopes=true
การรีเฟรชโทเค็นการเข้าถึง (การเข้าถึงแบบออฟไลน์)
โทเค็นการเข้าถึงจะหมดอายุเป็นระยะๆ และกลายเป็นข้อมูลเข้าสู่ระบบที่ไม่ถูกต้องสำหรับคำขอ API ที่เกี่ยวข้อง คุณสามารถรีเฟรชโทเค็นการเข้าถึงโดยไม่ต้องขอสิทธิ์จากผู้ใช้ (รวมถึงกรณีที่ผู้ใช้ไม่อยู่) ได้หากขอสิทธิ์เข้าถึงแบบออฟไลน์สำหรับขอบเขตที่เชื่อมโยงกับโทเค็น
- หากคุณใช้ไลบรารีของไคลเอ็นต์ Google API ออบเจ็กต์ไคลเอ็นต์จะรีเฟรชโทเค็นการเข้าถึงตามที่จำเป็น ตราบใดที่คุณกำหนดค่าออบเจ็กต์นั้นสำหรับการเข้าถึงแบบออฟไลน์
- หากไม่ได้ใช้ไลบรารีไคลเอ็นต์ คุณจะต้องตั้งค่าพารามิเตอร์การค้นหา
access_type
HTTP เป็น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 |
รหัสไคลเอ็นต์ที่ได้รับจาก |
client_secret |
รหัสลับไคลเอ็นต์ที่ได้รับจาก |
grant_type |
คุณต้องตั้งค่าช่องนี้เป็น refresh_token ตามที่ระบุไว้ในข้อกำหนดเฉพาะของ OAuth 2.0 |
refresh_token |
โทเค็นการรีเฟรชที่แสดงผลจากการแลกเปลี่ยนรหัสการให้สิทธิ์ |
ข้อมูลโค้ดต่อไปนี้แสดงคำขอตัวอย่าง
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded client_id=your_client_id& client_secret=your_client_secret& refresh_token=refresh_token& grant_type=refresh_token
ตราบใดที่ผู้ใช้ยังไม่ได้เพิกถอนสิทธิ์เข้าถึงที่มอบให้กับแอปพลิเคชัน เซิร์ฟเวอร์โทเค็นจะแสดงผลออบเจ็กต์ JSON ที่มีโทเค็นการเข้าถึงใหม่ ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างการตอบกลับ
{ "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 บริการนี้ช่วยให้คุณสมัครรับการแจ้งเตือนเหตุการณ์ด้านความปลอดภัยซึ่งจะส่งข้อมูลเกี่ยวกับการเปลี่ยนแปลงที่สำคัญในบัญชีผู้ใช้ไปยังแอปพลิเคชัน จากนั้น คุณสามารถใช้ข้อมูลดังกล่าวเพื่อดําเนินการโดยขึ้นอยู่กับวิธีตอบสนองต่อเหตุการณ์
ตัวอย่างประเภทเหตุการณ์ที่บริการการปกป้องบัญชีข้ามของ 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
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้การป้องกันแบบครอบคลุมหลายบริการและรายการเหตุการณ์ทั้งหมดที่ใช้ได้ได้จากหน้า ปกป้องบัญชีผู้ใช้ด้วยการป้องกันแบบครอบคลุมหลายบริการ