Tài liệu này giải thích cách các ứng dụng máy chủ web sử dụng Thư viện ứng dụng API của Google hoặc các điểm cuối OAuth 2.0 của Google để triển khai quy trình uỷ quyền OAuth 2.0 nhằm truy cập vào YouTube Data API.
OAuth 2.0 cho phép người dùng chia sẻ dữ liệu cụ thể với một ứng dụng trong khi vẫn giữ kín tên người dùng, mật khẩu và các thông tin khác. Ví dụ: một ứng dụng có thể sử dụng OAuth 2.0 để xin quyền tải video lên kênh YouTube của người dùng.
Quy trình OAuth 2.0 này dành riêng cho việc uỷ quyền của người dùng. Luồng này được thiết kế cho các ứng dụng có thể lưu trữ thông tin mật và duy trì trạng thái. Ứng dụng máy chủ web được uỷ quyền đúng cách có thể truy cập vào một API trong khi người dùng tương tác với ứng dụng hoặc sau khi người dùng rời khỏi ứng dụng.
Các ứng dụng máy chủ web cũng thường sử dụng
tài khoản dịch vụ để uỷ quyền cho các yêu cầu API, đặc biệt là khi gọi Cloud API để truy cập vào dữ liệu dựa trên dự án thay vì dữ liệu dành riêng cho người dùng. Các ứng dụng máy chủ web có thể sử dụng tài khoản dịch vụ kết hợp với quy trình uỷ quyền của người dùng.
Xin lưu ý rằng YouTube Data API chỉ hỗ trợ quy trình tài khoản dịch vụ cho
những chủ sở hữu nội dung trên YouTube sở hữu và quản lý nhiều kênh YouTube.
Cụ thể, chủ sở hữu nội dung có thể sử dụng tài khoản dịch vụ để gọi các phương thức API hỗ trợ tham số yêu cầu onBehalfOfContentOwner.
Thư viện ứng dụng
Các ví dụ theo ngôn ngữ cụ thể trên trang này sử dụng Thư viện ứng dụng API của Google để triển khai quy trình uỷ quyền OAuth 2.0. Để chạy mã mẫu, trước tiên, bạn phải cài đặt thư viện ứng dụng cho ngôn ngữ của mình.
Khi bạn sử dụng Thư viện ứng dụng API của Google để xử lý quy trình OAuth 2.0 của ứng dụng, thư viện ứng dụng sẽ thực hiện nhiều hành động mà ứng dụng cần tự xử lý. Ví dụ: phạm vi xác định thời điểm ứng dụng có thể sử dụng hoặc làm mới mã truy cập được lưu trữ, cũng như thời điểm ứng dụng phải lấy lại sự đồng ý. Thư viện ứng dụng cũng tạo URL chuyển hướng chính xác và giúp triển khai trình xử lý chuyển hướng để trao đổi mã uỷ quyền lấy mã truy cập.
Thư viện ứng dụng API của Google cho các ứng dụng phía máy chủ hỗ trợ các ngôn ngữ sau:
Điều kiện tiên quyết
Bật API cho dự án của bạn
Mọi ứng dụng gọi API của Google đều cần bật các API đó trong Bảng điều khiển API.
Cách bật API cho dự án:
- Mở Thư viện API trong Google API Console.
- Nếu bạn nhận được lời nhắc, hãy chọn một dự án hoặc tạo dự án mới.
- Sử dụng trang Thư viện để tìm và bật YouTube Data API. Tìm mọi API khác mà ứng dụng của bạn sẽ sử dụng và bật cả những API đó.
Tạo thông tin uỷ quyền
Bất kỳ ứng dụng nào sử dụng OAuth 2.0 để truy cập vào API của Google đều phải có thông tin xác thực uỷ quyền để xác định ứng dụng đó với máy chủ OAuth 2.0 của Google. Các bước sau đây giải thích cách tạo thông tin xác thực cho dự án của bạn. Sau đó, các ứng dụng của bạn có thể sử dụng thông tin đăng nhập để truy cập vào các API mà bạn đã bật cho dự án đó.
- Chuyển đến trang Ứng dụng.
- Nhấp vào Create Client (Tạo ứng dụng).
- Chọn loại ứng dụng Ứng dụng web.
- Điền thông tin vào biểu mẫu rồi nhấp vào Tạo. Các ứng dụng sử dụng ngôn ngữ và khung như PHP, Java, Python, Ruby và .NET phải chỉ định URI chuyển hướng được uỷ quyền. URI chuyển hướng là các điểm cuối mà máy chủ OAuth 2.0 có thể gửi phản hồi. Các điểm cuối này phải tuân thủ quy tắc xác thực của Google.
Để thử nghiệm, bạn có thể chỉ định các URI tham chiếu đến máy cục bộ, chẳng hạn như
http://localhost:8080. Tất cả ví dụ trong tài liệu này đều sử dụnghttp://localhost:8080làm URI chuyển hướng.Bạn nên thiết kế các điểm cuối xác thực của ứng dụng sao cho ứng dụng không hiển thị mã uỷ quyền cho các tài nguyên khác trên trang.
Sau khi tạo thông tin xác thực, hãy tải tệp client_secret.json xuống từ API Console. Lưu trữ tệp một cách an toàn ở vị trí mà chỉ ứng dụng của bạn mới có thể truy cập.
Xác định phạm vi truy cập
Phạm vi cho phép ứng dụng của bạn chỉ yêu cầu quyền truy cập vào những tài nguyên cần thiết, đồng thời cho phép người dùng kiểm soát mức độ truy cập mà họ cấp cho ứng dụng của bạn. Do đó, có thể có mối quan hệ nghịch đảo giữa số lượng phạm vi được yêu cầu và khả năng nhận được sự đồng ý của người dùng.
Trước khi bắt đầu triển khai quy trình uỷ quyền OAuth 2.0, bạn nên xác định các phạm vi mà ứng dụng của bạn cần có quyền truy cập.
Bạn cũng nên yêu cầu ứng dụng của mình yêu cầu quyền truy cập vào phạm vi uỷ quyền thông qua quy trình uỷ quyền gia tăng, trong đó ứng dụng của bạn yêu cầu quyền truy cập vào dữ liệu người dùng trong bối cảnh. Phương pháp hay nhất này giúp người dùng dễ dàng hiểu được lý do ứng dụng của bạn cần quyền truy cập mà ứng dụng đang yêu cầu.
YouTube Data API phiên bản 3 sử dụng các phạm vi sau:
| Phạm vi | Mô tả |
|---|---|
https://www. |
Quản lý tài khoản YouTube của bạn |
https://www. |
Xem danh sách các hội viên đang hoạt động trên kênh của bạn, cấp độ hiện tại của họ và thời điểm họ trở thành hội viên |
https://www. |
Xem, chỉnh sửa và xóa vĩnh viễn các video, mức xếp hạng, bình luận và phụ đề của bạn trên YouTube |
https://www. |
Xem tài khoản YouTube của bạn |
https://www. |
Quản lý video trên YouTube của bạn |
https://www. |
Xem và quản lý tài sản cũng như nội dung được kết hợp của bạn trên YouTube |
https://www. |
Xem thông tin riêng tư trên kênh YouTube của bạn có liên quan trong quá trình kiểm tra với đối tác YouTube |
Tài liệu Phạm vi API OAuth 2.0 chứa danh sách đầy đủ các phạm vi mà bạn có thể sử dụng để truy cập vào các API của Google.
Yêu cầu theo ngôn ngữ cụ thể
Để chạy bất kỳ mã mẫu nào trong tài liệu này, bạn cần có Tài khoản Google, quyền truy cập vào Internet và trình duyệt web. Nếu bạn đang sử dụng một trong các thư viện ứng dụng API, hãy xem các yêu cầu dành riêng cho ngôn ngữ trong các phần sau.
PHP
Để chạy các mã mẫu PHP trong tài liệu này, bạn cần:
- PHP 8.0 trở lên có cài đặt giao diện dòng lệnh (CLI) và tiện ích JSON.
- Công cụ quản lý phần phụ thuộc Composer.
-
Thư viện ứng dụng API của Google cho PHP:
composer require google/apiclient:^2.15.0
Hãy xem Thư viện ứng dụng API của Google cho PHP để biết thêm thông tin.
Python
Để chạy các mã mẫu Python trong tài liệu này, bạn cần:
- Python 3.7 trở lên
- Công cụ quản lý gói pip.
- Bản phát hành Thư viện ứng dụng Google API cho Python 2.0:
pip install --upgrade google-api-python-client
google-auth,google-auth-oauthlibvàgoogle-auth-httplib2để uỷ quyền cho người dùng.pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
- Khung ứng dụng web Flask Python.
pip install --upgrade flask
- Thư viện HTTP
requests.pip install --upgrade requests
Xem ghi chú phát hành của thư viện ứng dụng Python cho API của Google nếu bạn không thể nâng cấp Python và hướng dẫn di chuyển liên quan.
Ruby
Để chạy các mã mẫu Ruby trong tài liệu này, bạn cần:
- Ruby 2.6 trở lên
-
Thư viện xác thực của Google cho Ruby:
gem install googleauth
-
Khung ứng dụng web Sinatra Ruby.
gem install sinatra
Node.js
Để chạy các mã mẫu Node.js trong tài liệu này, bạn cần:
- Bản phát hành LTS bảo trì, LTS đang hoạt động hoặc bản phát hành hiện tại của Node.js.
-
Ứng dụng Node.js của API Google:
npm install googleapis crypto express express-session
HTTP/REST
Bạn không cần cài đặt bất kỳ thư viện nào để có thể gọi trực tiếp các điểm cuối OAuth 2.0.
Lấy mã truy cập OAuth 2.0
Các bước sau đây cho thấy cách ứng dụng của bạn tương tác với máy chủ OAuth 2.0 của Google để nhận được sự đồng ý của người dùng nhằm thực hiện yêu cầu API thay mặt cho người dùng. Ứng dụng của bạn phải có sự đồng ý đó trước khi có thể thực thi yêu cầu API của Google cần có sự uỷ quyền của người dùng.
Danh sách sau đây tóm tắt nhanh các bước này:
- Ứng dụng của bạn xác định các quyền mà ứng dụng cần.
- Ứng dụng của bạn chuyển hướng người dùng đến Google cùng với danh sách các quyền được yêu cầu.
- Người dùng quyết định xem có cấp quyền cho ứng dụng của bạn hay không.
- Ứng dụng của bạn sẽ tìm hiểu quyết định của người dùng.
- Nếu người dùng cấp các quyền được yêu cầu, ứng dụng của bạn sẽ truy xuất mã thông báo cần thiết để thay mặt người dùng đưa ra yêu cầu API.
Bước 1: Đặt tham số uỷ quyền
Bước đầu tiên là tạo yêu cầu uỷ quyền. Yêu cầu đó đặt các tham số xác định ứng dụng của bạn và xác định các quyền mà người dùng sẽ được yêu cầu cấp cho ứng dụng của bạn.
- Nếu sử dụng thư viện ứng dụng của Google để xác thực và uỷ quyền OAuth 2.0, bạn sẽ tạo và định cấu hình một đối tượng xác định các tham số này.
- Nếu gọi trực tiếp điểm cuối Google OAuth 2.0, bạn sẽ tạo một URL và đặt các tham số trên URL đó.
Các thẻ sau đây xác định các tham số uỷ quyền được hỗ trợ cho ứng dụng máy chủ web. Các ví dụ dành riêng cho ngôn ngữ cũng cho thấy cách sử dụng thư viện ứng dụng hoặc thư viện uỷ quyền để định cấu hình một đối tượng đặt các tham số đó:
PHP
Đoạn mã sau đây tạo một đối tượng Google\Client(), xác định các tham số trong yêu cầu uỷ quyền.
Đối tượng đó sử dụng thông tin trong tệp client_secret.json để xác định ứng dụng của bạn. (Xem phần tạo thông tin xác thực uỷ quyền để biết thêm thông tin về tệp đó.) Đối tượng này cũng xác định các phạm vi mà ứng dụng của bạn đang yêu cầu quyền truy cập và URL đến điểm cuối xác thực của ứng dụng, nơi sẽ xử lý phản hồi từ máy chủ OAuth 2.0 của Google. Cuối cùng, mã sẽ đặt các tham số access_type và include_granted_scopes không bắt buộc.
Ví dụ: mã này yêu cầu quyền truy cập khi không có mạng để quản lý tài khoản YouTube của người dùng:
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_YOUTUBE::YOUTUBE_FORCE_SSL); // 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
Đoạn mã sau đây sử dụng mô-đun google-auth-oauthlib.flow để tạo yêu cầu uỷ quyền.
Mã này tạo một đối tượng Flow, giúp xác định ứng dụng của bạn bằng thông tin trong tệp client_secret.json mà bạn đã tải xuống sau khi tạo thông tin xác thực. Đối tượng đó cũng xác định các phạm vi mà ứng dụng của bạn đang yêu cầu quyền truy cập và URL đến điểm cuối xác thực của ứng dụng, nơi sẽ xử lý phản hồi từ máy chủ OAuth 2.0 của Google. Cuối cùng, mã này sẽ đặt các tham số access_type và include_granted_scopes không bắt buộc.
Ví dụ: mã này yêu cầu quyền truy cập khi không có mạng để quản lý tài khoản YouTube của người dùng:
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/youtube.force-ssl']) # 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
Sử dụng tệp client_secrets.json mà bạn đã tạo để định cấu hình đối tượng ứng dụng trong ứng dụng của bạn. Khi định cấu hình đối tượng ứng dụng, bạn chỉ định các phạm vi mà ứng dụng cần truy cập, cùng với URL đến điểm cuối xác thực của ứng dụng. Điểm cuối này sẽ xử lý phản hồi từ máy chủ OAuth 2.0.
Ví dụ: mã này yêu cầu quyền truy cập khi không có mạng để quản lý tài khoản YouTube của người dùng:
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/youtube_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 scope = 'https://www.googleapis.com/auth/youtube.force-ssl' # 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)
Ứng dụng của bạn sử dụng đối tượng ứng dụng khách để thực hiện các thao tác OAuth 2.0, chẳng hạn như tạo URL yêu cầu uỷ quyền và áp dụng mã truy cập cho các yêu cầu HTTP.
Node.js
Đoạn mã sau đây tạo một đối tượng google.auth.OAuth2, xác định các tham số trong yêu cầu uỷ quyền.
Đối tượng đó sử dụng thông tin từ tệp client_secret.json để xác định ứng dụng của bạn. Để yêu cầu người dùng cấp quyền truy xuất mã truy cập, bạn hãy chuyển hướng họ đến trang đồng ý. Cách tạo URL trang lấy sự đồng ý:
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 YouTube API const scopes = [ 'https://www.googleapis.com/auth/youtube.force-ssl' ]; // 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 });
Lưu ý quan trọng – refresh_token chỉ được trả về trong lần uỷ quyền đầu tiên. Xem thêm thông tin
tại đây.
HTTP/REST
Điểm cuối OAuth 2.0 của Google là https://accounts.google.com/o/oauth2/v2/auth. Chỉ có thể truy cập điểm cuối này qua HTTPS. Các kết nối HTTP thuần tuý sẽ bị từ chối.
Máy chủ uỷ quyền của Google hỗ trợ các tham số chuỗi truy vấn sau đây cho các ứng dụng máy chủ web:
| Thông số | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
client_id |
Bắt buộc
Mã ứng dụng khách cho ứng dụng của bạn. Bạn có thể tìm thấy giá trị này trong trang Ứng dụng của Cloud Console. |
||||||||||||||||
redirect_uri |
Bắt buộc
Xác định nơi máy chủ API chuyển hướng người dùng sau khi người dùng hoàn tất quy trình uỷ quyền. Giá trị này phải khớp chính xác với một trong các URI chuyển hướng được uỷ quyền cho ứng dụng OAuth 2.0 mà bạn đã định cấu hình trong trang Ứng dụng của Cloud Console. Nếu giá trị này không khớp với một URI chuyển hướng được uỷ quyền cho Xin lưu ý rằng lược đồ |
||||||||||||||||
response_type |
Bắt buộc
Xác định xem điểm cuối Google OAuth 2.0 có trả về mã uỷ quyền hay không. Đặt giá trị tham số thành |
||||||||||||||||
scope |
Bắt buộc
Danh sách phạm vi được phân tách bằng dấu cách, xác định các tài nguyên mà ứng dụng của bạn có thể truy cập thay mặt cho người dùng. Các giá trị này thông báo cho màn hình xin phép mà Google hiển thị cho người dùng. Phạm vi cho phép ứng dụng của bạn chỉ yêu cầu quyền truy cập vào những tài nguyên cần thiết, đồng thời cho phép người dùng kiểm soát mức độ truy cập mà họ cấp cho ứng dụng của bạn. Do đó, có mối quan hệ nghịch đảo giữa số lượng phạm vi được yêu cầu và khả năng nhận được sự đồng ý của người dùng. YouTube Data API phiên bản 3 sử dụng các phạm vi sau:
Tài liệu Phạm vi API OAuth 2.0 cung cấp danh sách đầy đủ các phạm vi mà bạn có thể sử dụng để truy cập vào các API của Google. Bạn nên yêu cầu ứng dụng của mình cấp quyền truy cập vào phạm vi uỷ quyền trong bối cảnh bất cứ khi nào có thể. Bằng cách yêu cầu quyền truy cập vào dữ liệu người dùng trong bối cảnh, sử dụng tính năng uỷ quyền gia tăng, bạn sẽ giúp người dùng hiểu lý do ứng dụng của bạn cần quyền truy cập mà ứng dụng đang yêu cầu. |
||||||||||||||||
access_type |
Recommended (Nên dùng)
Cho biết liệu ứng dụng của bạn có thể làm mới mã truy cập khi người dùng không có mặt
tại trình duyệt hay không. Các giá trị tham số hợp lệ là Đặt giá trị thành |
||||||||||||||||
state |
Recommended (Nên dùng)
Chỉ định bất kỳ giá trị chuỗi nào mà ứng dụng của bạn sử dụng để duy trì trạng thái giữa yêu cầu uỷ quyền và phản hồi của máy chủ uỷ quyền.
Máy chủ trả về giá trị chính xác mà bạn gửi dưới dạng cặp Bạn có thể sử dụng tham số này cho một số mục đích, chẳng hạn như chuyển hướng người dùng đến
tài nguyên chính xác trong ứng dụng của bạn, gửi số chỉ dùng một lần và giảm thiểu hành vi giả mạo yêu cầu
trên nhiều trang web. Vì |
||||||||||||||||
include_granted_scopes |
Không bắt buộc
Cho phép các ứng dụng sử dụng quy trình uỷ quyền gia tăng để yêu cầu quyền truy cập vào các phạm vi bổ sung trong bối cảnh. Nếu bạn đặt giá trị của tham số này thành |
||||||||||||||||
enable_granular_consent |
Không bắt buộc
Giá trị mặc định là Khi Google bật quyền chi tiết cho một ứng dụng, tham số này sẽ không còn hiệu lực. |
||||||||||||||||
login_hint |
Không bắt buộc
Nếu ứng dụng của bạn biết người dùng nào đang cố gắng xác thực, thì ứng dụng có thể sử dụng tham số này để cung cấp gợi ý cho Máy chủ xác thực của Google. Máy chủ sử dụng gợi ý này để đơn giản hoá quy trình đăng nhập bằng cách điền sẵn trường email trong biểu mẫu đăng nhập hoặc bằng cách chọn phiên đăng nhập nhiều tài khoản phù hợp. Đặt giá trị tham số thành địa chỉ email hoặc giá trị nhận dạng |
||||||||||||||||
prompt |
Không bắt buộc
Danh sách lời nhắc được phân tách bằng dấu cách, có phân biệt chữ hoa chữ thường để hiển thị cho người dùng. Nếu bạn không chỉ định tham số này, người dùng sẽ chỉ được nhắc trong lần đầu tiên dự án của bạn yêu cầu quyền truy cập. Hãy xem phần Nhắc người dùng đồng ý lại để biết thêm thông tin. Các giá trị có thể là:
|
||||||||||||||||
Bước 2: Chuyển hướng đến máy chủ OAuth 2.0 của Google
Chuyển hướng người dùng đến máy chủ OAuth 2.0 của Google để bắt đầu quy trình xác thực và uỷ quyền. Thông thường, điều này xảy ra khi ứng dụng của bạn cần truy cập vào dữ liệu của người dùng lần đầu tiên. Trong trường hợp uỷ quyền gia tăng, bước này cũng xảy ra khi ứng dụng của bạn cần truy cập vào các tài nguyên bổ sung mà ứng dụng không có quyền truy cập.
PHP
- Tạo một URL để yêu cầu quyền truy cập từ máy chủ OAuth 2.0 của Google:
$auth_url = $client->createAuthUrl(); - Chuyển hướng người dùng đến
$auth_url:header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Python
Ví dụ này cho thấy cách chuyển hướng người dùng đến URL uỷ quyền bằng khung ứng dụng web Flask:
return flask.redirect(authorization_url)
Ruby
- Tạo một URL để yêu cầu quyền truy cập từ máy chủ OAuth 2.0 của Google:
auth_uri = authorizer.get_authorization_url(request: request)
- Chuyển hướng người dùng đến
auth_uri.
Node.js
-
Sử dụng URL được tạo
authorizationUrltừ phương thức Bước 1generateAuthUrlđể yêu cầu quyền truy cập từ máy chủ OAuth 2.0 của Google. -
Chuyển hướng người dùng đến
authorizationUrl.res.redirect(authorizationUrl);
HTTP/REST
Mẫu chuyển hướng đến máy chủ uỷ quyền của Google
URL mẫu bên dưới yêu cầu quyền truy cập xem không cần mạng (access_type=offline) vào một phạm vi cho phép truy cập để xem tài khoản YouTube của người dùng. Thư viện này sử dụng quy trình uỷ quyền gia tăng để đảm bảo rằng mã truy cập mới bao gồm mọi phạm vi mà người dùng đã cấp quyền truy cập cho ứng dụng trước đó. URL này cũng đặt giá trị cho các tham số bắt buộc redirect_uri, response_type và client_id cũng như cho tham số state. URL này chứa các dấu ngắt dòng và dấu cách để dễ đọc.
https://accounts.google.com/o/oauth2/v2/auth?
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly&
access_type=offline&
include_granted_scopes=true&
state=state_parameter_passthrough_value&
redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
response_type=code&
client_id=client_idSau khi bạn tạo URL yêu cầu, hãy chuyển hướng người dùng đến URL đó.
Máy chủ OAuth 2.0 của Google xác thực người dùng và xin sự đồng ý của người dùng để ứng dụng của bạn truy cập vào các phạm vi được yêu cầu. Phản hồi được gửi lại cho ứng dụng của bạn bằng URL chuyển hướng mà bạn đã chỉ định.
Bước 3: Google nhắc người dùng đồng ý
Trong bước này, người dùng quyết định xem có cấp cho ứng dụng của bạn quyền truy cập được yêu cầu hay không. Ở giai đoạn này, Google sẽ hiển thị một cửa sổ yêu cầu sự đồng ý, trong đó có tên ứng dụng của bạn và các dịch vụ API của Google mà ứng dụng đang yêu cầu quyền truy cập bằng thông tin xác thực của người dùng, cũng như thông tin tóm tắt về phạm vi truy cập sẽ được cấp. Sau đó, người dùng có thể đồng ý cấp quyền truy cập vào một hoặc nhiều phạm vi mà ứng dụng của bạn yêu cầu hoặc từ chối yêu cầu.
Ứng dụng của bạn không cần làm gì ở giai đoạn này vì ứng dụng đang chờ phản hồi từ máy chủ OAuth 2.0 của Google cho biết liệu có quyền truy cập nào được cấp hay không. Phản hồi đó được giải thích trong bước tiếp theo.
Lỗi
Yêu cầu gửi đến điểm cuối uỷ quyền OAuth 2.0 của Google có thể hiển thị thông báo lỗi dành cho người dùng thay vì quy trình xác thực và uỷ quyền dự kiến. Sau đây là các mã lỗi thường gặp và cách giải quyết đề xuất:
admin_policy_enforced
Tài khoản Google không thể uỷ quyền cho một hoặc nhiều phạm vi được yêu cầu do chính sách của quản trị viên Google Workspace. Hãy xem bài viết trợ giúp dành cho Quản trị viên Google Workspace Kiểm soát ứng dụng nội bộ và ứng dụng bên thứ ba nào có quyền truy cập vào dữ liệu trong Google Workspace để biết thêm thông tin về cách quản trị viên có thể hạn chế quyền truy cập vào tất cả phạm vi hoặc phạm vi nhạy cảm và bị hạn chế cho đến khi quyền truy cập được cấp rõ ràng cho mã ứng dụng khách OAuth của bạn.
disallowed_useragent
Điểm cuối uỷ quyền được hiển thị bên trong một tác nhân người dùng được nhúng không được Chính sách OAuth 2.0 của Google cho phép.
Nhà phát triển iOS và macOS có thể gặp lỗi này khi mở yêu cầu uỷ quyền trong WKWebView.
Thay vào đó, nhà phát triển nên sử dụng các thư viện iOS như Đăng nhập bằng Google cho iOS hoặc AppAuth cho iOS của OpenID Foundation.
Nhà phát triển web có thể gặp lỗi này khi một ứng dụng iOS hoặc macOS mở một đường liên kết trang web chung trong một tác nhân người dùng được nhúng và người dùng chuyển đến điểm cuối uỷ quyền OAuth 2.0 của Google từ trang web của bạn. Nhà phát triển nên cho phép các đường liên kết chung mở trong trình xử lý đường liên kết mặc định của hệ điều hành, bao gồm cả trình xử lý Đường liên kết phổ quát hoặc ứng dụng trình duyệt mặc định. Thư viện SFSafariViewController cũng là một lựa chọn được hỗ trợ.
org_internal
Mã ứng dụng OAuth trong yêu cầu là một phần của dự án giới hạn quyền truy cập vào Tài khoản Google trong một Tổ chức Google Cloud cụ thể. Để biết thêm thông tin về lựa chọn cấu hình này, hãy xem phần Loại người dùng trong bài viết trợ giúp Thiết lập màn hình xin phép bằng OAuth.
invalid_client
Khoá bí mật của ứng dụng OAuth không chính xác. Xem lại cấu hình ứng dụng OAuth, bao gồm cả mã ứng dụng khách và khoá bí mật dùng cho yêu cầu này.
deleted_client
Ứng dụng OAuth dùng để đưa ra yêu cầu đã bị xoá. Việc xoá có thể diễn ra theo cách thủ công hoặc tự động trong trường hợp máy khách không được sử dụng . Bạn có thể khôi phục khách hàng đã xoá trong vòng 30 ngày kể từ ngày xoá. Tìm hiểu thêm .
invalid_grant
Khi làm mới mã truy cập hoặc sử dụng quy trình uỷ quyền gia tăng, mã thông báo có thể đã hết hạn hoặc không hợp lệ. Xác thực lại người dùng và yêu cầu sự đồng ý của người dùng để nhận mã thông báo mới. Nếu bạn vẫn gặp lỗi này, hãy đảm bảo rằng ứng dụng của bạn đã được định cấu hình chính xác và bạn đang sử dụng đúng mã thông báo và tham số trong yêu cầu của mình. Nếu không, tài khoản người dùng có thể đã bị xoá hoặc bị vô hiệu hoá.
redirect_uri_mismatch
redirect_uri được truyền trong yêu cầu uỷ quyền không khớp với URI chuyển hướng được uỷ quyền cho mã ứng dụng OAuth. Xem lại các URI chuyển hướng được uỷ quyền trong trang Ứng dụng của Google Cloud Console.
Tham số redirect_uri có thể đề cập đến quy trình OAuth ngoài băng tần (OOB) đã ngừng hoạt động và không còn được hỗ trợ. Tham khảo hướng dẫn di chuyển để cập nhật chế độ tích hợp.
invalid_request
Đã xảy ra lỗi với yêu cầu của bạn. Điều này có thể là do một số lý do:
- Yêu cầu không được định dạng đúng cách
- Yêu cầu thiếu các tham số bắt buộc
- Yêu cầu này sử dụng một phương thức uỷ quyền mà Google không hỗ trợ. Xác minh rằng quá trình tích hợp OAuth của bạn sử dụng một phương thức tích hợp được đề xuất
Bước 4: Xử lý phản hồi của máy chủ OAuth 2.0
Máy chủ OAuth 2.0 phản hồi yêu cầu truy cập của ứng dụng bằng cách sử dụng URL được chỉ định trong yêu cầu.
Nếu người dùng phê duyệt yêu cầu truy cập, thì phản hồi sẽ chứa mã uỷ quyền. Nếu người dùng không phê duyệt yêu cầu, thì phản hồi sẽ chứa thông báo lỗi. Mã uỷ quyền hoặc thông báo lỗi được trả về máy chủ web sẽ xuất hiện trên chuỗi truy vấn, như trong các ví dụ sau:
Câu trả lời lỗi:
https://oauth2.example.com/auth?error=access_denied
Phản hồi mã uỷ quyền:
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
Phản hồi mẫu của máy chủ OAuth 2.0
Bạn có thể kiểm thử quy trình này bằng cách nhấp vào URL mẫu sau đây. URL này yêu cầu quyền chỉ có thể đọc để xem siêu dữ liệu của các tệp trong Google Drive và quyền chỉ có thể đọc để xem các sự kiện trên Lịch Google:
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.readonly& access_type=offline& include_granted_scopes=true& state=state_parameter_passthrough_value& redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback& response_type=code& client_id=client_id
Sau khi hoàn tất quy trình OAuth 2.0, trình duyệt sẽ chuyển hướng bạn đến OAuth 2.0 Playground, một công cụ để kiểm thử quy trình OAuth. Bạn sẽ thấy OAuth 2.0 Playground đã tự động thu thập mã uỷ quyền.
Bước 5: Đổi mã uỷ quyền lấy mã làm mới và mã truy cập
Sau khi nhận được mã uỷ quyền, máy chủ web có thể đổi mã uỷ quyền lấy mã truy cập.
PHP
Để đổi mã uỷ quyền lấy mã truy cập, hãy sử dụng phương thức fetchAccessTokenWithAuthCode:
$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);Python
Trên trang gọi lại, hãy sử dụng thư viện google-auth để xác minh phản hồi của máy chủ uỷ quyền. Sau đó, hãy sử dụng phương thức flow.fetch_token để đổi mã uỷ quyền trong phản hồi đó lấy mã truy cập:
state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/youtube.force-ssl'], 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
Trên trang gọi lại, hãy sử dụng thư viện googleauth để xác minh phản hồi của máy chủ uỷ quyền. Sử dụng phương thức authorizer.handle_auth_callback_deferred để lưu mã uỷ quyền và chuyển hướng trở lại URL ban đầu đã yêu cầu uỷ quyền. Thao tác này sẽ trì hoãn việc trao đổi mã bằng cách tạm thời lưu trữ kết quả trong phiên của người dùng.
target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request) redirect target_url
Node.js
Để đổi mã uỷ quyền lấy mã truy cập, hãy sử dụng phương thức 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
Để đổi mã uỷ quyền lấy mã truy cập, hãy gọi điểm cuối https://oauth2.googleapis.com/token và đặt các tham số sau:
| Trường | |
|---|---|
client_id |
Mã ứng dụng khách lấy từ trang Ứng dụng khách của Cloud Console. |
client_secret |
Không bắt buộc
Khoá bí mật của ứng dụng khách lấy từ trang Ứng dụng khách của Cloud Console. |
code |
Mã uỷ quyền được trả về từ yêu cầu ban đầu. |
grant_type |
Theo quy định trong thông số kỹ thuật của OAuth 2.0, giá trị của trường này phải được đặt thành authorization_code. |
redirect_uri |
Một trong các URI chuyển hướng được liệt kê cho dự án của bạn trong
trang Ứng dụng của
Cloud Console cho
client_id đã cho. |
Mặc dù việc sử dụng DPoP là không bắt buộc, nhưng bạn nên sử dụng để tăng cường bảo mật. Tính bảo mật của DPoP phụ thuộc vào việc khoá riêng tư chỉ được dùng cho một thiết bị; bạn nên lưu trữ khoá riêng tư theo cách không thể sao chép khoá đó ra khỏi thiết bị, chẳng hạn như bằng cách sử dụng TPM, Secure Enclave hoặc các kho khoá khác dựa trên phần cứng. Để sử dụng DPoP, ứng dụng của bạn phải tạo một JWT bằng chứng DPoP mới, duy nhất cho mỗi yêu cầu đến điểm cuối mã thông báo và thêm JWT đó làm tiêu đề yêu cầu HTTP.
| Tiêu đề | Bắt buộc | Mô tả |
|---|---|---|
DPoP |
Không bắt buộc | Bằng chứng DPoP là một JWT chứng minh quyền sở hữu khoá riêng tư. Đây là tiêu đề, không phải tham số. Nếu được cung cấp, mã thông báo được trả về sẽ liên kết với khoá này. Bạn phải tạo một bằng chứng mới, riêng biệt cho mỗi yêu cầu và
phải bao gồm các thông báo xác nhận quyền sở hữu htm (phương thức HTTP) và htu (URI HTTP)
khớp với yêu cầu. |
Đoạn mã sau đây cho thấy một yêu cầu mẫu:
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
Tạo bằng chứng DPoP
Các bước sau đây cho biết cách tạo bằng chứng DPoP bằng OpenSSL từ dòng lệnh:
- Tạo cặp khoá EC P-256:
openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
- Tạo tiêu đề DPoP:
Tiêu đề phải bao gồm các thông báo xác nhận quyền sở hữu
typ,algvàjwk(khoá công khai). Giá trịxvàylà toạ độ được mã hoá Base64Url của khoá công khai EC. Mã hoá Base64Url cho JSON này:{ "typ":"dpop+jwt", "alg":"ES256", "jwk": { "kty":"EC", "x":"YOUR_PUBLIC_KEY_X", "y":"YOUR_PUBLIC_KEY_Y", "crv":"P-256" } } - Tạo tải trọng DPoP:
Trọng tải phải bao gồm
jti(giá trị nhận dạng riêng biệt cho yêu cầu),htm(phương thức HTTP, ví dụ:POST),htu(URI HTTP, ví dụ:https://oauth2.googleapis.com/token) vàiat(thời điểm phát hành). Nếu nhận được số chỉ dùng một lần từ máy chủ trong tiêu đềDPoP-Noncekhi phản hồi một yêu cầu trước đó, thì bạn phải đưa giá trị số chỉ dùng một lần đó vào thông báo xác nhận quyền sở hữunonce. Xác nhận nonce là không bắt buộc đối với việc trao đổi mã uỷ quyền và chỉ được sử dụng khi tiêu đề DPoP-Nonce đã được nhận trước đó. Mã hoá Base64Url cho JSON này:{ "jti":"JTI_VALUE", "htm":"POST", "htu":"https://oauth2.googleapis.com/token", "iat":YOUR_JWT_ISSUED_TIME, "nonce":"SERVER_PROVIDED_NONCE" }Giá trị
jtiphụ thuộc vào loại sàn giao dịch:- Đối với hoạt động trao đổi mã uỷ quyền,
jtiphải là hàm băm SHA256 được mã hoá Base64Url của mã uỷ quyền:"jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))". - Đối với hoạt động trao đổi mã làm mới,
jtiphải là giá trị nhận dạng duy nhất cho mỗi yêu cầu:"jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER".
- Đối với hoạt động trao đổi mã uỷ quyền,
- Ký bằng chứng:
Nối tiêu đề và tải trọng đã mã hoá bằng dấu chấm (
.), sau đó ký kết quả bằng khoá riêng tư của bạn thông qua ES256. Xin lưu ý rằng JWS yêu cầu chữ ký phải ở định dạng nốiR | Sthô (64 byte cho P-256). Nếu sử dụng trực tiếp OpenSSL, bạn phải chuyển đổi chữ ký được mã hoá ASN.1 DER mặc định sang định dạng thô này.
Giao dịch trao đổi thành công được biểu thị bằng phản hồi 200 OK chứa mã thông báo. Nếu bạn sử dụng bằng chứng DPoP hợp lệ trong quá trình trao đổi, thì mã làm mới mà Google trả về sẽ được liên kết với khoá của bạn theo cơ chế DPoP, nhưng mã truy cập sẽ không được liên kết theo cơ chế DPoP. Mã truy cập sẽ giữ lại token_type của Bearer thay vì DPoP.
Ngoài ra, Google sẽ trả về tiêu đề HTTP DPoP-Nonce trong phản hồi.
Ứng dụng của bạn phải lưu trữ nonce này vào bộ nhớ đệm và đưa nonce này vào thông báo xác nhận quyền sở hữu nonce của bằng chứng DPoP trong các yêu cầu tiếp theo (chẳng hạn như khi đổi mã làm mới lấy mã truy cập mới hoặc khi gọi các API được DPoP bảo vệ). Bằng cách sử dụng số chỉ dùng một lần được cấp sớm này, bạn có thể tránh được lỗi khứ hồi bổ sung (use_dpop_nonce) trong yêu cầu tiếp theo.
Bạn phải cung cấp bằng chứng DPoP cho các yêu cầu trao đổi mã thông báo được thực hiện bằng mã làm mới liên kết với DPoP.
Lỗi trao đổi xảy ra nếu thiếu tiêu đề DPoP khi dự kiến, không hợp lệ hoặc nếu bằng chứng sử dụng khoá khác với khoá liên kết với mã thông báo. Trong những trường hợp này, máy chủ sẽ trả về lỗi 400 Bad Request.
Nếu bằng chứng DPoP có các thông báo xác nhận quyền sở hữu htm hoặc htu không khớp, iat đã hết hạn, jti được sử dụng lại hoặc chữ ký không hợp lệ, thì Google sẽ trả về mã lỗi invalid_dpop_proof.
Nếu cần có số chỉ dùng một lần DPoP, chẳng hạn như trong quá trình trao đổi mã làm mới và bằng chứng DPoP thiếu thông báo xác nhận quyền sở hữu nonce hoặc giá trị số chỉ dùng một lần không được máy chủ chấp nhận (ví dụ: đã hết hạn, đã được sử dụng hoặc không chính xác), thì Google sẽ trả về mã lỗi use_dpop_nonce cùng với tiêu đề HTTP DPoP-Nonce chứa số chỉ dùng một lần mới mà bạn có thể sử dụng trong yêu cầu tiếp theo.
Các lỗi khác có thể trả về invalid_grant.
Google phản hồi yêu cầu này bằng cách trả về một đối tượng JSON chứa mã truy cập ngắn hạn và mã làm mới.
Xin lưu ý rằng mã làm mới chỉ được trả về nếu ứng dụng của bạn đặt tham số access_type thành offline trong yêu cầu ban đầu gửi đến máy chủ uỷ quyền của Google.
Phản hồi chứa các trường sau:
| Trường | |
|---|---|
access_token |
Mã thông báo mà ứng dụng của bạn gửi để uỷ quyền cho một yêu cầu API của Google. |
expires_in |
Thời gian còn lại của mã truy cập tính bằng giây. |
refresh_token |
Mã thông báo mà bạn có thể dùng để lấy mã truy cập mới. Mã làm mới có hiệu lực cho đến khi người dùng thu hồi quyền truy cập hoặc mã làm mới hết hạn. Nếu bạn sử dụng DPoP, thì mã làm mới sẽ được liên kết với khoá riêng tư dùng để ký bằng chứng DPoP.
Xin nhắc lại, trường này chỉ xuất hiện trong phản hồi này nếu bạn đặt tham số access_type thành offline trong yêu cầu ban đầu gửi đến máy chủ uỷ quyền của Google.
|
refresh_token_expires_in |
Thời gian còn lại của mã làm mới tính bằng giây. Giá trị này chỉ được đặt khi người dùng cấp quyền truy cập theo thời gian. |
scope |
Phạm vi truy cập được access_token cấp, được biểu thị dưới dạng danh sách các chuỗi phân tách bằng dấu cách, có phân biệt chữ hoa chữ thường. |
token_type |
Loại mã thông báo được trả về. Giá trị này luôn là Bearer, ngay cả khi sử dụng DPoP. |
Đoạn mã sau đây cho thấy tiêu đề phản hồi và nội dung phản hồi thành công mẫu khi sử dụng 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/youtube.force-ssl",
"refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}Lỗi
Khi trao đổi mã uỷ quyền để lấy mã truy cập, bạn có thể gặp lỗi sau thay vì phản hồi như mong đợi. Các mã lỗi thường gặp và cách giải quyết đề xuất được liệt kê trong phần này.
invalid_grant
Mã uỷ quyền được cung cấp không hợp lệ hoặc có định dạng không chính xác. Yêu cầu mã mới bằng cách khởi động lại quy trình OAuth để nhắc người dùng đồng ý lại.
Bước 6: Kiểm tra xem người dùng đã cấp những phạm vi nào
Khi yêu cầu nhiều quyền (phạm vi), người dùng có thể không cấp cho ứng dụng của bạn quyền truy cập vào tất cả các quyền đó. Ứng dụng của bạn phải xác minh những phạm vi thực sự được cấp và xử lý linh hoạt các trường hợp một số quyền bị từ chối, thường là bằng cách tắt các tính năng dựa vào những phạm vi bị từ chối đó.
Tuy nhiên, vẫn có một số ngoại lệ. Các ứng dụng Google Workspace Enterprise có quyền uỷ quyền trên toàn miền hoặc các ứng dụng được đánh dấu là Đáng tin cậy sẽ bỏ qua màn hình xin phép cấp quyền truy cập chi tiết. Đối với những ứng dụng này, người dùng sẽ không thấy màn hình xin phép cấp quyền chi tiết. Thay vào đó, ứng dụng của bạn sẽ nhận được tất cả phạm vi được yêu cầu hoặc không nhận được phạm vi nào.
Để biết thêm thông tin chi tiết, hãy xem bài viết Cách xử lý các quyền truy cập chi tiết.
PHP
Để kiểm tra xem người dùng đã cấp những phạm vi nào, hãy sử dụng phương thức getGrantedScope():
// Space-separated string of granted scopes if it exists, otherwise null. $granted_scopes = $client->getOAuth2Service()->getGrantedScope();
Python
Đối tượng credentials được trả về có thuộc tính granted_scopes, là danh sách các phạm vi mà người dùng đã cấp cho ứng dụng của bạn.
credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes}
Ruby
Khi yêu cầu nhiều phạm vi cùng một lúc, hãy kiểm tra xem phạm vi nào đã được cấp thông qua thuộc tính scope của đối tượng credentials.
# User authorized the request. Now, check which scopes were granted. if credentials.scope.include?(Google::Apis::YoutubeV3::AUTH_YOUTUBE_FORCE_SSL) # User authorized permission to see, edit, and permanently delete the # YouTube videos, ratings, comments and captions. # Calling the APIs, etc else # User didn't authorize the permission. # Update UX and application accordingly end
Node.js
Khi yêu cầu nhiều phạm vi cùng một lúc, hãy kiểm tra xem phạm vi nào đã được cấp thông qua thuộc tính scope của đối tượng tokens.
// User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/youtube.force-ssl')) { // User authorized permission to see, edit, and permanently delete the // YouTube videos, ratings, comments and captions. // Calling the APIs, etc. } else { // User didn't authorize read-only Drive activity permission. // Update UX and application accordingly }
HTTP/REST
Để kiểm tra xem người dùng đã cấp cho ứng dụng của bạn quyền truy cập vào một phạm vi cụ thể hay chưa, hãy kiểm tra trường scope trong phản hồi mã truy cập. Phạm vi truy cập được cấp bởi
mã truy cập được biểu thị dưới dạng danh sách các chuỗi phân biệt chữ hoa chữ thường, được phân tách bằng dấu cách.
Ví dụ: phản hồi mã truy cập mẫu sau đây cho biết rằng người dùng đã cấp cho ứng dụng của bạn quyền xem, chỉnh sửa và xoá vĩnh viễn video trên YouTube, điểm xếp hạng, bình luận và phụ đề của người dùng:
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/youtube.force-ssl", "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
Gọi API của Google
PHP
Sử dụng mã truy cập để gọi API của Google bằng cách hoàn tất các bước sau:
- Nếu bạn cần áp dụng mã truy cập cho một đối tượng
Google\Clientmới (ví dụ: nếu bạn lưu trữ mã truy cập trong một phiên người dùng), hãy sử dụng phương thứcsetAccessToken:$client->setAccessToken($access_token); - Tạo một đối tượng dịch vụ cho API mà bạn muốn gọi. Bạn tạo một đối tượng dịch vụ bằng cách cung cấp đối tượng
Google\Clientđược uỷ quyền cho hàm khởi tạo của API mà bạn muốn gọi. Ví dụ: để gọi YouTube Data API, hãy làm như sau:$youtube = new Google_Service_YouTube($client); - Tạo yêu cầu đến dịch vụ API bằng cách sử dụng
giao diện do đối tượng dịch vụ cung cấp.
Ví dụ: Để truy xuất dữ liệu về kênh YouTube của người dùng được uỷ quyền, hãy làm như sau:
$channel = $youtube->channels->listChannels('snippet', array('mine' => $mine));
Python
Sau khi nhận được mã truy cập, ứng dụng của bạn có thể sử dụng mã đó để uỷ quyền cho các yêu cầu API thay mặt cho một tài khoản người dùng hoặc tài khoản dịch vụ nhất định. Sử dụng thông tin uỷ quyền dành riêng cho người dùng để tạo đối tượng dịch vụ cho API mà bạn muốn gọi, sau đó sử dụng đối tượng đó để thực hiện các yêu cầu API được uỷ quyền.
- Tạo một đối tượng dịch vụ cho API mà bạn muốn gọi. Bạn tạo một đối tượng dịch vụ bằng cách gọi phương thức
buildcủa thư việngoogleapiclient.discoverybằng tên và phiên bản của API cũng như thông tin đăng nhập của người dùng: Ví dụ: để gọi phiên bản 3 của YouTube Data API:from googleapiclient.discovery import build youtube = build('youtube', 'v3', credentials=credentials)
- Tạo yêu cầu đến dịch vụ API bằng cách sử dụng giao diện do đối tượng dịch vụ cung cấp.
Ví dụ: Để truy xuất dữ liệu về kênh YouTube của người dùng được uỷ quyền, hãy làm như sau:
channel = youtube.channels().list(mine=True, part='snippet').execute()
Ruby
Sau khi nhận được mã truy cập, ứng dụng của bạn có thể sử dụng mã đó để thực hiện các yêu cầu API thay mặt cho một tài khoản người dùng hoặc tài khoản dịch vụ nhất định. Sử dụng thông tin uỷ quyền dành riêng cho người dùng để tạo đối tượng dịch vụ cho API mà bạn muốn gọi, sau đó sử dụng đối tượng đó để thực hiện các yêu cầu API được uỷ quyền.
- Tạo một đối tượng dịch vụ cho API mà bạn muốn gọi.
Ví dụ: để gọi phiên bản 3 của YouTube Data API:
youtube = Google::Apis::YoutubeV3::YouTubeService.new
- Đặt thông tin xác thực trên dịch vụ:
youtube.authorization = credentials
- Gửi yêu cầu đến dịch vụ API bằng cách sử dụng giao diện do đối tượng dịch vụ cung cấp.
Ví dụ: Để truy xuất dữ liệu về kênh YouTube của người dùng được uỷ quyền, hãy làm như sau:
channel = youtube.list_channels(part, :mine => mine)
Ngoài ra, bạn có thể cung cấp thông tin uỷ quyền theo từng phương thức bằng cách cung cấp tham số options cho một phương thức:
channel = youtube.list_channels(part, :mine => mine, options: { authorization: auth_client })
Node.js
Sau khi lấy được mã truy cập và đặt mã đó cho đối tượng OAuth2, hãy sử dụng đối tượng đó để gọi các API của Google. Ứng dụng của bạn có thể sử dụng mã thông báo đó để uỷ quyền cho các yêu cầu API thay mặt cho một tài khoản người dùng hoặc tài khoản dịch vụ nhất định. Tạo một đối tượng dịch vụ cho API mà bạn muốn gọi.
Ví dụ: mã sau đây sử dụng API Google Drive để liệt kê tên tệp trong Drive của người dùng.
const { google } = require('googleapis'); // Example of using YouTube API to list channels. var service = google.youtube('v3'); service.channels.list({ auth: oauth2Client, part: 'snippet,contentDetails,statistics', forUsername: 'GoogleDevelopers' }, function (err, response) { if (err) { console.log('The API returned an error: ' + err); return; } var channels = response.data.items; if (channels.length == 0) { console.log('No channel found.'); } else { console.log('This channel\'s ID is %s. Its title is \'%s\', and ' + 'it has %s views.', channels[0].id, channels[0].snippet.title, channels[0].statistics.viewCount); } });
HTTP/REST
Sau khi ứng dụng của bạn nhận được mã truy cập, bạn có thể sử dụng mã này để thực hiện lệnh gọi đến một API của Google thay mặt cho một tài khoản người dùng nhất định nếu(các) phạm vi truy cập mà API yêu cầu đã được cấp. Để thực hiện việc này, hãy thêm mã truy cập vào yêu cầu gửi đến API bằng cách thêm tham số truy vấn access_token hoặc giá trị Bearer của tiêu đề HTTP Authorization. Nếu có thể, bạn nên sử dụng tiêu đề HTTP vì chuỗi truy vấn có xu hướng hiển thị trong nhật ký máy chủ. Trong hầu hết các trường hợp, bạn có thể sử dụng thư viện ứng dụng để thiết lập lệnh gọi đến API của Google (ví dụ: khi gọi API Dữ liệu của YouTube).
Xin lưu ý rằng YouTube Data API chỉ hỗ trợ tài khoản dịch vụ cho những chủ sở hữu nội dung trên YouTube sở hữu và quản lý nhiều kênh YouTube, chẳng hạn như hãng thu âm và hãng phim.
Bạn có thể dùng thử tất cả API của Google và xem phạm vi của các API đó tại OAuth 2.0 Playground.
Ví dụ về HTTP GET
Lệnh gọi đến điểm cuối
youtube.channels (YouTube Data API) sử dụng tiêu đề HTTP Authorization: Bearer có thể có dạng như sau. Lưu ý rằng bạn cần chỉ định mã truy cập của riêng mình:
GET /youtube/v3/channels?part=snippet&mine=true HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
Dưới đây là lệnh gọi đến cùng một API cho người dùng đã xác thực bằng tham số chuỗi truy vấn access_token:
GET https://www.googleapis.com/youtube/v3/channels?access_token=access_token&part=snippet&mine=true
Ví dụ về curl
Bạn có thể kiểm thử các lệnh này bằng ứng dụng dòng lệnh curl. Sau đây là ví dụ sử dụng lựa chọn tiêu đề HTTP (ưu tiên):
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true
Hoặc, bạn có thể chọn tham số chuỗi truy vấn:
curl https://www.googleapis.com/youtube/v3/channels?access_token=access_token&part=snippet&mine=true
Ví dụ đầy đủ
Ví dụ sau đây in một đối tượng có định dạng JSON cho thấy thông tin về kênh YouTube của người dùng sau khi người dùng xác thực và cho phép ứng dụng quản lý tài khoản YouTube của người dùng.
PHP
Cách chạy ví dụ này:
- Trong API Console, hãy thêm URL của máy cục bộ vào danh sách URL chuyển hướng. Ví dụ: thêm
http://localhost:8080. - Tạo một thư mục mới và chuyển sang thư mục đó. Ví dụ:
mkdir ~/php-oauth2-example cd ~/php-oauth2-example
- Cài đặt Thư viện ứng dụng API của Google cho PHP bằng Composer:
composer require google/apiclient:^2.15.0
- Tạo các tệp
index.phpvàoauth2callback.phpcó nội dung sau. - Chạy ví dụ bằng máy chủ web thử nghiệm tích hợp sẵn của 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']); $youtube = new Google_Service_YouTube($client); $channel = $youtube->channels->listChannels('snippet', array('mine' => $mine)); echo json_encode($channel); } 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_YOUTUBE::YOUTUBE_FORCE_SSL); // 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(); $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
Ví dụ này sử dụng khung Flask. Công cụ này chạy một ứng dụng web tại http://localhost:8080, cho phép bạn kiểm thử quy trình OAuth 2.0. Nếu truy cập vào URL đó, bạn sẽ thấy 5 đường liên kết:
- Kiểm tra yêu cầu API: Đường liên kết này trỏ đến một trang cố gắng thực thi một yêu cầu API mẫu. Nếu cần, ứng dụng sẽ bắt đầu quy trình uỷ quyền. Nếu thành công, trang sẽ hiển thị phản hồi của API.
- Kiểm tra trực tiếp quy trình uỷ quyền: Đường liên kết này trỏ đến một trang cố gắng đưa người dùng vào quy trình uỷ quyền. Ứng dụng yêu cầu quyền gửi các yêu cầu API được uỷ quyền thay mặt cho người dùng.
- Thu hồi thông tin xác thực hiện tại: Đường liên kết này trỏ đến một trang thu hồi các quyền mà người dùng đã cấp cho ứng dụng.
- Xoá thông tin đăng nhập của phiên Flask: Đường liên kết này xoá thông tin đăng nhập uỷ quyền được lưu trữ trong phiên Flask. Thao tác này cho phép bạn xem điều gì sẽ xảy ra nếu người dùng đã cấp quyền cho ứng dụng của bạn cố gắng thực thi một yêu cầu API trong phiên mới. Công cụ này cũng cho phép bạn xem phản hồi của API mà ứng dụng của bạn sẽ nhận được nếu người dùng thu hồi các quyền đã cấp cho ứng dụng của bạn và ứng dụng của bạn vẫn cố gắng uỷ quyền cho một yêu cầu bằng mã truy cập đã bị thu hồi.
# -*- 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/youtube.force-ssl'] API_SERVICE_NAME = 'youtube' API_VERSION = 'v3' 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('/test') def test_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') # Load credentials from the session. credentials = google.oauth2.credentials.Credentials( **flask.session['credentials']) youtube = googleapiclient.discovery.build( API_SERVICE_NAME, API_VERSION, credentials=credentials) channel = youtube.channels().list(mine=True, part='snippet').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(**channel) @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 flask.session['credentials'] = credentials_to_dict(credentials) return flask.redirect(flask.url_for('test_api_request')) @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 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="/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 Google API Console. app.run('localhost', 8080, debug=True)
Ruby
Ví dụ này sử dụng khung Sinatra.
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/youtube_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 retrieving data about the user's YouTube channel. scope = 'Google::Apis::YoutubeV3::AUTH_YOUTUBE_FORCE_SSL' # 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 read-only YouTube Data API permission. # Example of using YouTube Data API to list user's YouTube channel youtube = Google::Apis::YoutubeV3::YouTubeService.new channel = youtube.list_channels(part, :mine => mine, options: { authorization: auth_client }) "<pre>#{JSON.pretty_generate(channel.to_h)}</pre>" 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
Cách chạy ví dụ này:
-
Trong API Console, hãy thêm URL của máy cục bộ vào danh sách URL chuyển hướng. Ví dụ: thêm
http://localhost. - Hãy đảm bảo bạn đã cài đặt phiên bản LTS bảo trì, LTS đang hoạt động hoặc bản phát hành hiện tại của Node.js.
-
Tạo một thư mục mới và chuyển sang thư mục đó. Ví dụ:
mkdir ~/nodejs-oauth2-example cd ~/nodejs-oauth2-example
-
Cài đặt
Thư viện ứng dụng API của Google
cho Node.js bằng npm:
npm install googleapis
-
Tạo tệp
main.jscó nội dung sau. -
Chạy ví dụ:
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 YouTube API const scopes = [ 'https://www.googleapis.com/auth/youtube.force-ssl' ]; /* 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; // Example of using YouTube API to list channels. var service = google.youtube('v3'); service.channels.list({ auth: oauth2Client, part: 'snippet,contentDetails,statistics', forUsername: 'GoogleDevelopers' }, function (err, response) { if (err) { console.log('The API returned an error: ' + err); return; } var channels = response.data.items; if (channels.length == 0) { console.log('No channel found.'); } else { console.log('This channel\'s ID is %s. Its title is \'%s\', and ' + 'it has %s views.', channels[0].id, channels[0].snippet.title, channels[0].statistics.viewCount); } }); } }); // 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
Ví dụ về Python này sử dụng khung Flask và thư viện Requests để minh hoạ quy trình web OAuth 2.0. Bạn nên sử dụng Thư viện ứng dụng API của Google cho Python cho quy trình này. (Ví dụ trong thẻ Python có sử dụng thư viện ứng dụng.)
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 YouTube API SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl' # 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: headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])} req_uri = 'https://www.googleapis.com/youtube/v3/channels/list' r = requests.get(req_uri, headers=headers) return r.text @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()
Quy tắc xác thực URI chuyển hướng
Google áp dụng các quy tắc xác thực sau đây cho URI chuyển hướng để giúp nhà phát triển bảo mật ứng dụng của họ. URI chuyển hướng của bạn phải tuân thủ các quy tắc này. Xem RFC 3986 mục 3 để biết định nghĩa về miền, máy chủ lưu trữ, đường dẫn, truy vấn, lược đồ và thông tin người dùng được sử dụng trong các quy tắc này.
| Các quy tắc xác thực | |
|---|---|
| Lược đồ |
URI chuyển hướng phải sử dụng giao thức HTTPS, không phải HTTP thông thường. URI máy chủ cục bộ (bao gồm cả URI địa chỉ IP máy chủ cục bộ) được miễn áp dụng quy tắc này. |
| Người tổ chức |
Máy chủ lưu trữ không được là địa chỉ IP thô. Địa chỉ IP của máy chủ cục bộ được miễn áp dụng quy tắc này. |
| Miền |
“googleusercontent.com”.goo.gl) trừ phi
ứng dụng sở hữu miền đó. Hơn nữa, nếu một ứng dụng sở hữu miền rút gọn chọn chuyển hướng đến miền đó, thì URI chuyển hướng đó phải chứa “/google-callback/” trong đường dẫn hoặc kết thúc bằng “/google-callback”. |
| Userinfo |
URI chuyển hướng không được chứa thành phần phụ userinfo. |
| Đường dẫn |
URI chuyển hướng không được chứa đường dẫn truyền tải (còn gọi là quay lui thư mục), được biểu thị bằng |
| Cụm từ tìm kiếm |
URI chuyển hướng không được chứa lệnh chuyển hướng mở. |
| Fragment |
URI chuyển hướng không được chứa thành phần phân đoạn. |
| Ký tự |
URI chuyển hướng không được chứa một số ký tự, bao gồm:
|
Uỷ quyền gia tăng
Trong giao thức OAuth 2.0, ứng dụng của bạn yêu cầu uỷ quyền truy cập vào các tài nguyên được xác định theo phạm vi. Bạn nên yêu cầu cấp quyền truy cập vào tài nguyên tại thời điểm cần thiết để mang lại trải nghiệm tốt nhất cho người dùng. Để hỗ trợ phương pháp này, máy chủ uỷ quyền của Google hỗ trợ uỷ quyền gia tăng. Tính năng này cho phép bạn yêu cầu các phạm vi khi cần và nếu người dùng cấp quyền cho phạm vi mới, tính năng này sẽ trả về một mã uỷ quyền có thể được đổi lấy mã thông báo chứa tất cả các phạm vi mà người dùng đã cấp cho dự án.
Ví dụ: giả sử một ứng dụng giúp người dùng xác định các sự kiện thú vị tại địa phương. Ứng dụng này cho phép người dùng xem video về các sự kiện, xếp hạng video và thêm video vào danh sách phát. Người dùng cũng có thể sử dụng ứng dụng này để thêm sự kiện vào Lịch Google của họ.
Trong trường hợp này, tại thời điểm đăng nhập, ứng dụng có thể không cần hoặc không yêu cầu quyền truy cập vào bất kỳ phạm vi nào. Tuy nhiên, nếu người dùng cố gắng xếp hạng video, thêm video vào danh sách phát hoặc thực hiện một hành động khác trên YouTube, thì ứng dụng có thể yêu cầu quyền truy cập vào phạm vi https://www.googleapis.com/auth/youtube.force-ssl.
Tương tự, ứng dụng có thể yêu cầu quyền truy cập vào phạm vi https://www.googleapis.com/auth/calendar nếu người dùng cố gắng thêm một sự kiện trên lịch.
Để triển khai quy trình uỷ quyền gia tăng, bạn hoàn tất quy trình thông thường để yêu cầu mã truy cập nhưng hãy đảm bảo rằng yêu cầu uỷ quyền bao gồm các phạm vi đã được cấp trước đó. Cách tiếp cận này giúp ứng dụng của bạn không phải quản lý nhiều mã truy cập.
Các quy tắc sau đây áp dụng cho mã truy cập có được từ quy trình uỷ quyền gia tăng:
- Bạn có thể dùng mã thông báo này để truy cập vào các tài nguyên tương ứng với bất kỳ phạm vi nào được đưa vào quy trình uỷ quyền mới, kết hợp.
- Khi bạn sử dụng mã làm mới cho yêu cầu uỷ quyền kết hợp để lấy mã truy cập, mã truy cập này sẽ đại diện cho yêu cầu uỷ quyền kết hợp và có thể được dùng cho bất kỳ giá trị
scopenào có trong phản hồi. - Uỷ quyền kết hợp bao gồm tất cả các phạm vi mà người dùng đã cấp cho dự án API ngay cả khi các quyền được yêu cầu từ các ứng dụng khác nhau. Ví dụ: nếu người dùng cấp quyền truy cập vào một phạm vi bằng ứng dụng khách trên máy tính của một ứng dụng, sau đó cấp một phạm vi khác cho cùng một ứng dụng đó thông qua ứng dụng di động, thì thông tin uỷ quyền kết hợp sẽ bao gồm cả hai phạm vi.
- Nếu bạn thu hồi một mã thông báo đại diện cho một yêu cầu uỷ quyền kết hợp, thì quyền truy cập vào tất cả phạm vi của yêu cầu uỷ quyền đó thay mặt cho người dùng được liên kết sẽ bị thu hồi đồng thời.
Các mã mẫu theo ngôn ngữ cụ thể trong Bước 1: Đặt lệnh chuyển hướng uỷ quyền đến máy chủ OAuth 2.0 của Google đều sử dụng quy trình uỷ quyền gia tăng. Các mã mẫu sau đây cũng cho thấy mã bạn cần thêm để sử dụng quy trình uỷ quyền gia tăng.
PHP
$client->setIncludeGrantedScopes(true);Python
Trong Python, hãy đặt đối số từ khoá include_granted_scopes thành true để đảm bảo rằng yêu cầu uỷ quyền bao gồm các phạm vi đã được cấp trước đó. Rất có thể include_granted_scopes không phải là đối số từ khoá duy nhất mà bạn đặt, như trong ví dụ dưới đây.
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
Trong ví dụ này, ứng dụng gọi yêu cầu quyền truy cập để truy xuất dữ liệu YouTube Analytics của người dùng, ngoài bất kỳ quyền truy cập nào khác mà người dùng đã cấp cho ứng dụng.
GET https://accounts.google.com/o/oauth2/v2/auth?
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyt-analytics.readonly&
access_type=offline&
state=security_token%3D138rk%3Btarget_url%3Dhttp...index&
redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
response_type=code&
client_id=client_id&
include_granted_scopes=true
Refresh an access token (offline access)
Access tokens periodically expire and become invalid credentials for a related API request. You can refresh an access token without prompting the user for permission (including when the user is not present) if you requested offline access to the scopes associated with the token.
- If you use a Google API Client Library, the client object refreshes the access token as needed as long as you configure that object for offline access.
- If you are not using a client library, you need to set the
access_typeHTTP query parameter toofflinewhen redirecting the user to Google's OAuth 2.0 server. In that case, Google's authorization server returns a refresh token when you exchange an authorization code for an access token. Then, if the access token expires (or at any other time), you can use a refresh token to obtain a new access token.
Requesting offline access is a requirement for any application that needs to access a Google
API when the user is not present. For example, an app that performs backup services or
executes actions at predetermined times needs to be able to refresh its access token when the
user is not present. The default style of access is called online.
Server-side web applications, installed applications, and devices all obtain refresh tokens during the authorization process. Refresh tokens are not typically used in client-side (JavaScript) web applications.
PHP
If your application needs offline access to a Google API, set the API client's access type to
offline:
$client->setAccessType("offline");
Sau khi người dùng cấp quyền truy cập khi không có mạng cho các phạm vi được yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập vào các API của Google thay mặt cho người dùng khi người dùng không có mạng. Đối tượng ứng dụng khách sẽ làm mới mã truy cập nếu cần.
Python
Trong Python, hãy đặt đối số từ khoá access_type thành offline để đảm bảo rằng bạn có thể làm mới mã truy cập mà không cần nhắc lại người dùng để xin cấp quyền. Rất có thể access_type sẽ không phải là đối số từ khoá duy nhất mà bạn đặt, như trong ví dụ dưới đây.
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')
Sau khi người dùng cấp quyền truy cập khi không có mạng cho các phạm vi được yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập vào các API của Google thay mặt cho người dùng khi người dùng không có mạng. Đối tượng ứng dụng khách sẽ làm mới mã truy cập nếu cần.
Ruby
Nếu ứng dụng của bạn cần quyền truy cập ngoại tuyến vào một API của Google, hãy đặt loại quyền truy cập của ứng dụng API thành
offline:
auth_client.update!( :additional_parameters => {"access_type" => "offline"} )
Sau khi người dùng cấp quyền truy cập khi không có mạng cho các phạm vi được yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập vào các API của Google thay mặt cho người dùng khi người dùng không có mạng. Đối tượng ứng dụng khách sẽ làm mới mã truy cập nếu cần.
Node.js
Nếu ứng dụng của bạn cần quyền truy cập ngoại tuyến vào một API của Google, hãy đặt loại quyền truy cập của ứng dụng API thành
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 });
Sau khi người dùng cấp quyền truy cập khi không có mạng cho các phạm vi được yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập vào các API của Google thay mặt cho người dùng khi người dùng không có mạng. Đối tượng ứng dụng khách sẽ làm mới mã truy cập nếu cần.
Mã truy cập sẽ hết hạn. Thư viện này sẽ tự động sử dụng mã làm mới để lấy mã truy cập mới nếu mã truy cập sắp hết hạn. Một cách dễ dàng để đảm bảo bạn luôn lưu trữ các mã thông báo mới nhất là sử dụng sự kiện mã thông báo:
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); });
Sự kiện mã thông báo này chỉ xảy ra trong lần uỷ quyền đầu tiên và bạn cần đặt access_type thành offline khi gọi phương thức generateAuthUrl để nhận mã làm mới. Nếu đã cấp cho ứng dụng các quyền cần thiết mà không đặt ra các quy tắc ràng buộc thích hợp để nhận mã làm mới, bạn sẽ cần uỷ quyền lại cho ứng dụng để nhận mã làm mới mới.
Để đặt refresh_token vào lúc khác, bạn có thể sử dụng phương thức setCredentials:
oauth2Client.setCredentials({ refresh_token: `STORED_REFRESH_TOKEN` });
Sau khi ứng dụng có mã làm mới, mã truy cập sẽ được lấy và làm mới tự động trong lệnh gọi tiếp theo đến API.
HTTP/REST
Để làm mới mã truy cập, ứng dụng của bạn sẽ gửi một yêu cầu HTTPS POST đến máy chủ uỷ quyền của Google (https://oauth2.googleapis.com/token) có chứa các tham số sau trong phần nội dung yêu cầu:
| Tên | Giá trị |
|---|---|
client_id |
Mã ứng dụng khách lấy từ API Console. |
client_secret |
Không bắt buộc
Khoá bí mật của ứng dụng khách lấy được từ API Console. |
grant_type |
Như
được xác định trong
quy cách của OAuth 2.0,
giá trị của trường này phải được đặt thành refresh_token. |
refresh_token |
Mã làm mới được trả về từ quá trình trao đổi mã uỷ quyền. |
Mặc dù việc sử dụng DPoP là không bắt buộc, nhưng bạn nên sử dụng để tăng cường bảo mật. Để sử dụng DPoP với mã làm mới, ứng dụng của bạn phải tạo một JWT bằng chứng DPoP mới, duy nhất cho mỗi yêu cầu đến điểm cuối mã thông báo. Bằng chứng này phải được ký bằng cùng một khoá riêng tư đã được dùng trong quá trình trao đổi mã uỷ quyền ban đầu. Ứng dụng của bạn thêm bằng chứng dưới dạng tiêu đề của yêu cầu HTTP.
| Tiêu đề | Bắt buộc | Mô tả |
|---|---|---|
DPoP |
Không bắt buộc | Bằng chứng DPoP là một JWT chứng minh quyền sở hữu khoá riêng tư. Đây là tiêu đề, không phải tham số. Nếu được cung cấp, mã thông báo được trả về sẽ liên kết với khoá này. Bạn phải tạo một bằng chứng mới, riêng biệt cho mỗi yêu cầu và
phải bao gồm các thông báo xác nhận quyền sở hữu htm (phương thức HTTP) và htu (URI HTTP)
khớp với yêu cầu. |
Đoạn mã sau đây cho thấy một yêu cầu mẫu:
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
Để sử dụng DPoP với mã làm mới, bạn phải tạo một JWT bằng chứng DPoP mới, duy nhất cho yêu cầu. Hãy xem phần Tạo bằng chứng DPoP để biết hướng dẫn từng bước về cách tạo cặp khoá và tạo JWT.
Giao dịch trao đổi thành công được biểu thị bằng phản hồi 200 OK chứa mã truy cập mới. Khi sử dụng DPoP, token_type là Bearer. Phản hồi thành công xác nhận rằng bằng chứng DPoP cho mã làm mới đã được chấp nhận. Google cũng có thể trả về một tiêu đề HTTP DPoP-Nonce mới trong phản hồi; nếu được trả về, ứng dụng của bạn phải lưu số chỉ dùng một lần này vào bộ nhớ đệm và đưa số đó vào thông báo xác nhận quyền sở hữu nonce của bằng chứng DPoP trong các yêu cầu tiếp theo.
Lượt trao đổi không thành công xảy ra nếu tiêu đề DPoP bị thiếu, không hợp lệ hoặc sử dụng khoá không chính xác. Để biết thông tin chi tiết về các mã lỗi DPoP cụ thể và cách xử lý số chỉ dùng một lần, hãy xem phần Trao đổi không thành công.
Đoạn mã sau đây cho thấy tiêu đề phản hồi và nội dung phản hồi thành công mẫu khi sử dụng 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",
"token_type": "Bearer"
}Xin lưu ý rằng có giới hạn về số lượng mã làm mới sẽ được cấp; một giới hạn cho mỗi tổ hợp ứng dụng khách/người dùng và một giới hạn khác cho mỗi người dùng trên tất cả ứng dụng khách. Bạn nên lưu mã làm mới trong bộ nhớ dài hạn và tiếp tục sử dụng mã đó miễn là mã vẫn còn hiệu lực. Nếu ứng dụng của bạn yêu cầu quá nhiều mã làm mới, thì ứng dụng có thể đạt đến các giới hạn này. Trong trường hợp đó, các mã làm mới cũ hơn sẽ ngừng hoạt động.
Thu hồi mã thông báo
Trong một số trường hợp, người dùng có thể muốn thu hồi quyền truy cập đã cấp cho một ứng dụng. Người dùng có thể thu hồi quyền truy cập bằng cách truy cập vào phần Cài đặt tài khoản. Hãy xem phần Xoá quyền truy cập của trang web hoặc ứng dụng trong tài liệu hỗ trợ Các trang web và ứng dụng bên thứ ba có quyền truy cập vào tài khoản của bạn để biết thêm thông tin.
Ứng dụng cũng có thể thu hồi quyền truy cập được cấp cho ứng dụng đó theo phương thức lập trình. Việc thu hồi theo chương trình là rất quan trọng trong trường hợp người dùng huỷ đăng ký, xoá một ứng dụng hoặc tài nguyên API mà ứng dụng yêu cầu đã thay đổi đáng kể. Nói cách khác, một phần của quy trình xoá có thể bao gồm yêu cầu API để đảm bảo các quyền đã cấp trước đó cho ứng dụng sẽ bị xoá.
PHP
Để thu hồi mã thông báo theo phương thức lập trình, hãy gọi revokeToken():
$client->revokeToken();Python
Để thu hồi mã thông báo theo phương thức lập trình, hãy gửi yêu cầu đến https://oauth2.googleapis.com/revoke, trong đó có mã thông báo dưới dạng tham số và đặt tiêu đề Content-Type:
requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'})
Ruby
Để thu hồi mã thông báo theo phương thức lập trình, hãy gửi một yêu cầu HTTP đến điểm cuối oauth2.revoke:
uri = URI('https://oauth2.googleapis.com/revoke') response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
Mã thông báo có thể là mã truy cập hoặc mã làm mới. Nếu mã thông báo là mã truy cập và có mã làm mới tương ứng, thì mã làm mới cũng sẽ bị thu hồi.
Nếu yêu cầu thu hồi được xử lý thành công, thì mã trạng thái của phản hồi là 200. Đối với các điều kiện lỗi, mã trạng thái 400 sẽ được trả về cùng với mã lỗi.
Node.js
Để thu hồi mã thông báo theo phương thức lập trình, hãy gửi yêu cầu HTTPS POST đến điểm cuối /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();
Tham số mã thông báo có thể là mã truy cập hoặc mã làm mới. Nếu mã thông báo là mã truy cập và có mã làm mới tương ứng, thì mã làm mới cũng sẽ bị thu hồi.
Nếu yêu cầu thu hồi được xử lý thành công, thì mã trạng thái của phản hồi là 200. Đối với các điều kiện lỗi, mã trạng thái 400 sẽ được trả về cùng với mã lỗi.
HTTP/REST
Để thu hồi mã thông báo theo phương thức lập trình, ứng dụng của bạn sẽ gửi một yêu cầu đến https://oauth2.googleapis.com/revoke và đưa mã thông báo vào làm tham số:
curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
https://oauth2.googleapis.com/revoke?token={token}Mã thông báo có thể là mã truy cập hoặc mã làm mới. Nếu mã thông báo là mã truy cập và có mã làm mới tương ứng, thì mã làm mới cũng sẽ bị thu hồi.
Nếu yêu cầu thu hồi được xử lý thành công, thì mã trạng thái HTTP của phản hồi sẽ là 200. Đối với các điều kiện lỗi, mã trạng thái HTTP 400 sẽ được trả về cùng với mã lỗi.
Quyền truy cập theo thời gian
Quyền truy cập theo thời gian cho phép người dùng cấp cho ứng dụng của bạn quyền truy cập vào dữ liệu của họ trong một khoảng thời gian có hạn để hoàn tất một hành động. Quyền truy cập theo thời gian được cung cấp trong một số sản phẩm của Google trong quy trình đồng ý, cho phép người dùng cấp quyền truy cập trong một khoảng thời gian giới hạn. Ví dụ: Data Portability API cho phép chuyển dữ liệu một lần.
Khi người dùng cấp cho ứng dụng của bạn quyền truy cập theo thời gian, mã làm mới sẽ hết hạn sau
khoảng thời gian được chỉ định. Xin lưu ý rằng mã làm mới có thể bị vô hiệu sớm hơn trong một số trường hợp cụ thể; hãy xem các trường hợp này để biết thông tin chi tiết. Trường refresh_token_expires_in được trả về trong phản hồi trao đổi mã uỷ quyền thể hiện thời gian còn lại cho đến khi mã làm mới hết hạn trong những trường hợp như vậy.
Triển khai tính năng Bảo vệ nhiều tài khoản
Một bước bổ sung mà bạn nên thực hiện để bảo vệ tài khoản của người dùng là triển khai tính năng Bảo vệ nhiều tài khoản bằng cách sử dụng Dịch vụ bảo vệ nhiều tài khoản của Google. Dịch vụ này cho phép bạn đăng ký nhận thông báo sự kiện bảo mật, cung cấp thông tin cho ứng dụng của bạn về những thay đổi lớn đối với tài khoản người dùng. Sau đó, bạn có thể sử dụng thông tin này để hành động tuỳ thuộc vào cách bạn quyết định phản hồi các sự kiện.
Sau đây là một số ví dụ về các loại sự kiện mà Dịch vụ bảo vệ nhiều tài khoản của Google gửi đến ứng dụng của bạn:
-
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
Hãy xem trang Bảo vệ tài khoản người dùng bằng tính năng Bảo vệ nhiều tài khoản để biết thêm thông tin về cách triển khai tính năng Bảo vệ nhiều tài khoản và xem danh sách đầy đủ các sự kiện hiện có.