Sử dụng OAuth 2.0 cho các ứng dụng máy chủ web

Tài liệu này giải thích cách các ứng dụng máy chủ web sử dụng các 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 OAuth 2.0 cho phép truy cập vào các API của Google.

OAuth 2.0 cho phép người dùng chia sẻ dữ liệu cụ thể với một ứng dụng, đồng thời giữ bí mật 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 phép người dùng lưu trữ tệp trong Google Drive của họ.

Luồng OAuth 2.0 này dành riêng cho việc ủy quyền người dùng. Ứng dụng này được thiết kế cho những ứ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 ủy quyền đúng cách có thể truy cập 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ụ để cho phép các yêu cầu API, đặc biệt là khi gọi API Cloud để truy cập dữ liệu dựa trên dự án thay vì dữ liệu theo từng 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ụ cùng với sự cho phép của người dùng.

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 lệnh ủy 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ý luồng OAuth 2.0 của ứng dụng, thư viện ứng dụng khách sẽ thực hiện nhiều thao tác mà ứng dụng cần tự xử lý. Ví dụ: tỷ lệ này sẽ xác định thời điểm ứng dụng có thể sử dụng hoặc làm mới mã thông báo truy cập đã 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ã ủy quyền cho mã truy cập.

Các thư viện ứng dụng API của Google cho các ứng dụng phía máy chủ hiện có sẵn cho những 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 phải bật các API đó trong API Console.

Cách bật API cho dự án:

  1. Open the API Library trong Google API Console.
  2. If prompted, select a project, or create a new one.
  3. API Library Danh sách tất cả API có sẵn, được nhóm theo nhóm sản phẩm và mức độ phổ biến. Nếu API bạn muốn bật không hiển thị trong danh sách, hãy sử dụng tính năng tìm kiếm để tìm API đó hoặc nhấp vào Xem tất cả trong nhóm sản phẩm chứa API đó.
  4. Chọn API bạn muốn bật, sau đó nhấp vào nút Bật.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

Tạo thông tin đăng nhập ủy quyền

Bất kỳ ứng dụng nào sử dụng OAuth 2.0 để truy cập API của Google đều phải có thông tin đăng nhập ủy quyền để nhận dạng ứng dụng đó bằng máy chủ OAuth 2.0 của Google. Sau đây là các bước giải thích cách tạo thông tin đăng nhập 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 xác thực để truy cập các API mà bạn đã bật cho dự án đó.

  1. Go to the Credentials page.
  2. Nhấp vào Tạo thông tin xác thực > Mã ứng dụng OAuth.
  3. Chọn loại ứng dụng Ứng dụng web.
  4. Điền thông tin vào biểu mẫu, rồi nhấp vào Tạo. Những ứng dụng sử dụng các ngôn ngữ và khung như PHP, Java, Python, Ruby và .NET phải chỉ định URI chuyển hướng được ủy 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. Xin lưu ý rằng tất cả các ví dụ trong tài liệu này sử dụng http://localhost:8080 làm URI chuyển hướng.

    Bạn nên thiết kế điểm cuối xác thực của ứng dụng để ứng dụng của bạn không để lộ mã ủy 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 các tài nguyên cần thiết, đồng thời cho phép người dùng kiểm soát số lượng quyền 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 đã yêu cầu và khả năng có được sự đồng ý của người dùng.

Trước khi bắt đầu triển khai ủy 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 sẽ cần quyền truy cập.

Bạn cũng nên yêu cầu quyền truy cập vào phạm vi ủy quyền thông qua một quy trình ủy 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 theo ngữ 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.

Tài liệu về Phạm vi API OAuth 2.0 chứa danh sách đầy đủ các phạm vi mà bạn có thể dùng để truy cập vào các API của Google.

Yêu cầu dành riêng cho từng ngôn ngữ

Để chạy bất kỳ mẫu mã nào trong tài liệu này, bạn cần có Tài khoản Google, có kết nối Internet và một 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 thêm các yêu cầu đối với ngôn ngữ cụ thể bên dưới.

PHP

Để chạy mẫu mã PHP trong tài liệu này, bạn cần:

  • PHP 5.4 trở lên khi 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 Soạn thư.
  • Thư viện ứng dụng API Google cho PHP:

    php composer.phar require google/apiclient:^2.0

Python

Để chạy mẫu mã Python trong tài liệu này, bạn cần:

  • Python 2.6 trở lên
  • Công cụ quản lý gói pip.
  • Thư viện ứng dụng Python cho các API của Google:
    pip install --upgrade google-api-python-client
  • google-auth, google-auth-oauthlibgoogle-auth-httplib2 để cho phép 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

Ruby

Để chạy các mẫu mã Ruby trong tài liệu này, bạn cần:

  • Ruby 2.2.2 trở lên
  • Thư viện ứng dụng API của Google cho Ruby:

    gem install google-api-client
  • Khung ứng dụng web Sinatra Ruby.

    gem install sinatra

Node.js

Để chạy mẫu mã Node.js trong tài liệu này, bạn cầ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.
  • Ứng dụng Google API Node.js:

    npm install googleapis

HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

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 đ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 để thực hiện yêu cầu API thay mặt người dùng. Ứng dụng của bạn phải có được sự đồng ý đó thì mới có thể thực thi yêu cầu API của Google yêu cầu sự cho phép của người dùng.

Danh sách bên dưới tóm tắt nhanh các bước sau:

  1. Ứng dụng của bạn xác định các quyền mà ứng dụng cần.
  2. Ứ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.
  3. Người dùng sẽ quyết định cấp quyền cho ứng dụng của bạn hay không.
  4. Ứng dụng của bạn tìm hiểu những gì người dùng quyết định.
  5. 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 cho người dùng gửi yêu cầu API.

Bước 1: Đặt thông số ủy quyền

Bước đầu tiên là tạo yêu cầu ủy quyền. Yêu cầu đó sẽ đặt các thông số xác định ứng dụng của bạn và xác định những 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 dùng thư viện ứng dụng Google để xác thực và ủy 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ẻ bên dưới xác định những thông số ủy quyền được hỗ trợ cho các ứng dụng máy chủ web. Các ví dụ cụ thể về ngôn ngữ cũng cho thấy cách sử dụng thư viện ứng dụng hoặc thư viện ủy quyền để định cấu hình một đối tượng có đặt các thông số đó.

PHP

Đoạn mã bên dưới tạo một đối tượng Google_Client() để xác định các thông số trong yêu cầu ủy quyền.

Đối tượng đó sử dụng thông tin từ tệp client_secret.json của bạn để xác định ứng dụng. (Xem phần tạo thông tin cấp phép để biết thêm 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. Thao tác này sẽ xử lý phản hồi từ máy chủ OAuth 2.0 của Google. Cuối cùng, mã này đặt các thông số access_typeinclude_granted_scopes (không bắt buộc).

Ví dụ: mã này yêu cầu quyền truy cập chỉ đọc, ngoại tuyến vào Google Drive của người dùng:

$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
// 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');
// Using "consent" ensures that your application always receives a refresh token.
// If you are not using offline access, you can omit this.
$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true);   // incremental auth

Yêu cầu này chỉ định những thông tin sau:

Các thông số
client_id Bắt buộc

ID ứ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 Credentials page API Console.

Trong PHP, hãy gọi hàm setAuthConfig để tải thông tin cấp phép từ tệp client_secret.json.

$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
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 thành luồng ủy 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 ủy quyền của ứng dụng OAuth 2.0 mà bạn đã định cấu hình trong API Consolecủa Credentials page. Nếu giá trị này không khớp với URI chuyển hướng được ủy quyền cho client_id đã cho, bạn sẽ gặp lỗi redirect_uri_mismatch.

Xin lưu ý rằng lược đồ http hoặc https, cách viết hoa và dấu gạch chéo theo sau (×39;/#39;) phải khớp hoàn toàn.

Để đặt giá trị này bằng PHP, hãy gọi hàm setRedirectUri. Xin lưu ý rằng bạn phải chỉ định URI chuyển hướng hợp lệ cho client_id đã cung cấp.

$client->setRedirectUri('https://oauth2.example.com/code');
scope Bắt buộc

Danh sách các 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. Những giá trị này cho biết màn hình đồng ý 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 các tài nguyên cần thiết, đồng thời cho phép người dùng kiểm soát số lượng quyền 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 đã yêu cầu và khả năng có được sự đồng ý của người dùng.

Để đặt giá trị này bằng PHP, hãy gọi hàm addScope:

$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

Yêu cầu ứng dụng của bạn yêu cầu quyền truy cập vào phạm vi ủy quyền theo ngữ 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 theo bối cảnh, thông qua quy trình ủy quyền gia tăng, bạn giúp người dùng dễ dàng hơn để hiểu lý do ứng dụng của bạn cần quyền truy cập vào ứng dụng.

access_type Nên

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 trên trình duyệt hay không. Các giá trị thông số hợp lệ là online, là giá trị mặc định và offline.

Đặt giá trị thành offline nếu ứng dụng của bạn cần làm mới mã thông báo truy cập khi người dùng không có mặt trên trình duyệt. Đây là phương pháp làm mới mã truy cập được mô tả ở phần sau trong tài liệu này. Giá trị này hướng dẫn máy chủ ủy quyền của Google trả về một mã làm mới mã truy cập cho lần đầu tiên ứng dụng của bạn trao đổi mã ủy quyền cho mã thông báo.

Để đặt giá trị này bằng PHP, hãy gọi hàm setAccessType:

$client->setAccessType('offline');
state Nên

Chỉ định mọi giá trị chuỗi mà ứng dụng dùng để duy trì trạng thái giữa yêu cầu ủy quyền của bạn và phản hồi của máy chủ ủy quyền. Máy chủ trả về giá trị chính xác mà bạn gửi dưới dạng một cặp name=value trong thành phần truy vấn URL (?) của redirect_uri sau khi người dùng đồng ý hoặc từ chối yêu cầu truy cập của ứng dụng.

Bạn có thể sử dụng thông số này cho nhiều 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 nonces và giảm thiểu hành vi giả mạo yêu cầu trên nhiều trang web. Vì redirect_uri của bạn có thể được đoán ra, nên việc sử dụng giá trị state có thể làm tăng mức độ chắc chắn của bạn rằng kết nối đến là kết quả của một yêu cầu xác thực. Nếu bạn tạo một chuỗi ngẫu nhiên hoặc mã hóa giá trị băm của cookie hoặc giá trị khác thu thập trạng thái của ứng dụng, thì bạn có thể xác thực phản hồi để đảm bảo rằng yêu cầu và phản hồi bắt nguồn trong cùng một trình duyệt, qua đó bảo vệ bạn khỏi các cuộc tấn công như giả mạo yêu cầu trên nhiều trang web. Hãy xem tài liệu về OpenID Connect để xem ví dụ về cách tạo và xác nhận mã thông báo state.

Để đặt giá trị này bằng PHP, hãy gọi hàm setState:

$client->setState($sample_passthrough_value);
include_granted_scopes Tùy chọn

Cho phép các ứng dụng dùng thông tin ủy 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 thông số này là true và yêu cầu ủy quyền được cấp, thì mã truy cập mới cũng sẽ đề cập đến mọi phạm vi mà người dùng trước đây đã cấp quyền truy cập vào ứng dụng. Hãy xem phần ủy quyền gia hạn để biết ví dụ.

Để đặt giá trị này bằng PHP, hãy gọi hàm setIncludeGrantedScopes:

$client->setIncludeGrantedScopes(true);
login_hint Tùy chọn

Nếu biết ứng dụng nào đang cố gắng xác thực, ứng dụng của bạn có thể sử dụng thông 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 giản hóa 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 thích hợp.

Đặt giá trị thông số thành địa chỉ email hoặc giá trị nhận dạng sub, tương đương với mã nhận dạng Google của người dùng.

Để đặt giá trị này bằng PHP, hãy gọi hàm setLoginHint:

$client->setLoginHint('None');
prompt Tùy chọn

Danh sách lời nhắc có phân biệt chữ hoa chữ thường và được phân tách bằng dấu cách để 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 vào 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 lại sự đồng ý để biết thêm thông tin.

Để đặt giá trị này bằng PHP, hãy gọi hàm setApprovalPrompt:

$client->setApprovalPrompt('consent');

Các giá trị có thể là:

none Không hiển thị bất kỳ màn hình xác thực hoặc màn hình đồng ý nào. Không được chỉ định cùng với các giá trị khác.
consent Nhắc người dùng đồng ý.
select_account Nhắc người dùng chọn tài khoản.

Python

Đoạn mã sau sử dụng mô-đun google-auth-oauthlib.flow để tạo yêu cầu ủy quyền.

Mã này tạo một đối tượng Flow để xác định ứng dụng của bạn bằng cách sử dụng thông tin từ tệp client_secret.json mà bạn đã tải xuống sau khi tạo thông tin xác thực ủy quyền. Đối tượng đó cũng xác định 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. Thao tác này 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 thông số access_typeinclude_granted_scopes (không bắt buộc).

Ví dụ: mã này yêu cầu quyền truy cập chỉ đọc, ngoại tuyến vào Google Drive của người dùng:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Use the client_secret.json file to identify the application requesting
# authorization. The client ID (from that file) and access scopes are required.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.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.
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(
    # 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')

Yêu cầu này chỉ định những thông tin sau:

Các thông số
client_id Bắt buộc

ID ứ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 Credentials page API Console.

Trong Python, hãy gọi phương thức from_client_secrets_file để truy xuất mã ứng dụng từ tệp client_secret.json. (Bạn cũng có thể sử dụng phương thức from_client_config để chuyển cấu hình ứng dụng giống như phương thức xuất hiện ban đầu trong tệp khóa bí mật của ứng dụng nhưng không truy cập vào tệp đó.)

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])
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 thành luồng ủy 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 ủy quyền của ứng dụng OAuth 2.0 mà bạn đã định cấu hình trong API Consolecủa Credentials page. Nếu giá trị này không khớp với URI chuyển hướng được ủy quyền cho client_id đã cho, bạn sẽ gặp lỗi redirect_uri_mismatch.

Xin lưu ý rằng lược đồ http hoặc https, cách viết hoa và dấu gạch chéo theo sau (×39;/#39;) phải khớp hoàn toàn.

Để đặt giá trị này bằng Python, hãy đặt thuộc tính redirect_uri của đối tượng flow:

flow.redirect_uri = 'https://oauth2.example.com/code'
scope Bắt buộc

Danh sách các phạm vi 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. Những giá trị này cho biết màn hình đồng ý 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 các tài nguyên cần thiết, đồng thời cho phép người dùng kiểm soát số lượng quyền 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 đã yêu cầu và khả năng có được sự đồng ý của người dùng.

Trong Python, hãy dùng phương thức mà bạn dùng để đặt client_id để chỉ định danh sách các phạm vi.

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

Yêu cầu ứng dụng của bạn yêu cầu quyền truy cập vào phạm vi ủy quyền theo ngữ 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 theo bối cảnh, thông qua quy trình ủy quyền gia tăng, bạn giúp người dùng dễ dàng hơn để hiểu lý do ứng dụng của bạn cần quyền truy cập vào ứng dụng.

access_type Nên

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 trên trình duyệt hay không. Các giá trị thông số hợp lệ là online, là giá trị mặc định và offline.

Đặt giá trị thành offline nếu ứng dụng của bạn cần làm mới mã thông báo truy cập khi người dùng không có mặt trên trình duyệt. Đây là phương pháp làm mới mã truy cập được mô tả ở phần sau trong tài liệu này. Giá trị này hướng dẫn máy chủ ủy quyền của Google trả về một mã làm mới mã truy cập cho lần đầu tiên ứng dụng của bạn trao đổi mã ủy quyền cho mã thông báo.

Trong Python, hãy đặt thông số access_type bằng cách chỉ định access_type làm đối số từ khóa khi gọi phương thức flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
state Nên

Chỉ định mọi giá trị chuỗi mà ứng dụng dùng để duy trì trạng thái giữa yêu cầu ủy quyền của bạn và phản hồi của máy chủ ủy quyền. Máy chủ trả về giá trị chính xác mà bạn gửi dưới dạng một cặp name=value trong thành phần truy vấn URL (?) của redirect_uri sau khi người dùng đồng ý hoặc từ chối yêu cầu truy cập của ứng dụng.

Bạn có thể sử dụng thông số này cho nhiều 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 nonces và giảm thiểu hành vi giả mạo yêu cầu trên nhiều trang web. Vì redirect_uri của bạn có thể được đoán ra, nên việc sử dụng giá trị state có thể làm tăng mức độ chắc chắn của bạn rằng kết nối đến là kết quả của một yêu cầu xác thực. Nếu bạn tạo một chuỗi ngẫu nhiên hoặc mã hóa giá trị băm của cookie hoặc giá trị khác thu thập trạng thái của ứng dụng, thì bạn có thể xác thực phản hồi để đảm bảo rằng yêu cầu và phản hồi bắt nguồn trong cùng một trình duyệt, qua đó bảo vệ bạn khỏi các cuộc tấn công như giả mạo yêu cầu trên nhiều trang web. Hãy xem tài liệu về OpenID Connect để xem ví dụ về cách tạo và xác nhận mã thông báo state.

Trong Python, hãy đặt thông số state bằng cách chỉ định state làm đối số từ khóa khi gọi phương thức flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    state=sample_passthrough_value,
    include_granted_scopes='true')
include_granted_scopes Tùy chọn

Cho phép các ứng dụng dùng thông tin ủy 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 thông số này là true và yêu cầu ủy quyền được cấp, thì mã truy cập mới cũng sẽ đề cập đến mọi phạm vi mà người dùng trước đây đã cấp quyền truy cập vào ứng dụng. Hãy xem phần ủy quyền gia hạn để biết ví dụ.

Trong Python, hãy đặt thông số include_granted_scopes bằng cách chỉ định include_granted_scopes làm đối số từ khóa khi gọi phương thức flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
login_hint Tùy chọn

Nếu biết ứng dụng nào đang cố gắng xác thực, ứng dụng của bạn có thể sử dụng thông 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 giản hóa 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 thích hợp.

Đặt giá trị thông số thành địa chỉ email hoặc giá trị nhận dạng sub, tương đương với mã nhận dạng Google của người dùng.

Trong Python, hãy đặt thông số login_hint bằng cách chỉ định login_hint làm đối số từ khóa khi gọi phương thức flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    login_hint='None',
    include_granted_scopes='true')
prompt Tùy chọn

Danh sách lời nhắc có phân biệt chữ hoa chữ thường và được phân tách bằng dấu cách để 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 vào 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 lại sự đồng ý để biết thêm thông tin.

Trong Python, hãy đặt thông số prompt bằng cách chỉ định prompt làm đối số từ khóa khi gọi phương thức flow.authorization_url:

authorization_url, state = flow.authorization_url(
      access_type='offline',
      prompt='consent',
      include_granted_scopes='true')

Các giá trị có thể là:

none Không hiển thị bất kỳ màn hình xác thực hoặc màn hình đồng ý nào. Không được chỉ định cùng với các giá trị khác.
consent Nhắc người dùng đồng ý.
select_account Nhắc người dùng chọn tài khoản.

Ruby

Sử dụng tệp client_secrets.json mà bạn đã tạo để định cấu hình một đối tượng client trong ứng dụng của bạn. Khi định cấu hình đối tượng máy khách, bạn chỉ định những phạm vi mà ứng dụng của bạn cần truy cập, cùng với URL đến điểm cuối xác thực của ứng dụng. Thao tác 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 chỉ đọc, ngoại tuyến vào Google Drive của người dùng:

require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'

client_secrets = Google::APIClient::ClientSecrets.load
auth_client = client_secrets.to_authorization
auth_client.update!(
  :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly',
  :redirect_uri => 'http://www.example.com/oauth2callback',
  :additional_parameters => {
    "access_type" => "offline",         # offline access
    "include_granted_scopes" => "true"  # incremental auth
  }
)

Ứng dụng của bạn sử dụng đối tượng máy 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 ủy quyền và áp dụng mã thông báo truy cập cho các yêu cầu HTTP.

Node.js

Đoạn mã bên dưới tạo một đối tượng google.auth.OAuth2 để xác định các thông số trong yêu cầu ủy 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 phải chuyển hướng họ đến trang đồng ý. Cách tạo URL trang đồng ý:

const {google} = require('googleapis');

/**
 * 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 read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];

// Generate a url that asks permissions for the Drive activity 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
});

Lưu ý quan trọngrefresh_token chỉ được trả về trong lần ủy quyền đầu tiên. Tìm hiểu thêm thông tin tại đây.

HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

Điểm cuối OAuth 2.0 của Google đang ở https://accounts.google.com/o/oauth2/v2/auth. Bạn chỉ có thể truy cập điểm cuối này qua HTTPS. Kết nối HTTP thuần túy bị từ chối.

Máy chủ ủy quyền của Google hỗ trợ các tham số chuỗi truy vấn sau cho các ứng dụng máy chủ web:

Các thông số
client_id Bắt buộc

ID ứ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 Credentials page API 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 thành luồng ủy 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 ủy quyền của ứng dụng OAuth 2.0 mà bạn đã định cấu hình trong API Consolecủa Credentials page. Nếu giá trị này không khớp với URI chuyển hướng được ủy quyền cho client_id đã cho, bạn sẽ gặp lỗi redirect_uri_mismatch.

Xin lưu ý rằng lược đồ http hoặc https, cách viết hoa và dấu gạch chéo theo sau (×39;/#39;) phải khớp hoàn toàn.

response_type Bắt buộc

Xác định điểm cuối của Google OAuth 2.0 có trả về mã ủy quyền hay không.

Đặt giá trị thông số thành code cho các ứng dụng máy chủ web.

scope Bắt buộc

Danh sách các 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. Những giá trị này cho biết màn hình đồng ý 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 các tài nguyên cần thiết, đồng thời cho phép người dùng kiểm soát số lượng quyền 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 đã yêu cầu và khả năng có được sự đồng ý của người dùng.

Yêu cầu ứng dụng của bạn yêu cầu quyền truy cập vào phạm vi ủy quyền theo ngữ 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 theo bối cảnh, thông qua quy trình ủy quyền gia tăng, bạn giúp người dùng dễ dàng hơn để hiểu lý do ứng dụng của bạn cần quyền truy cập vào ứng dụng.

access_type Nên

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 trên trình duyệt hay không. Các giá trị thông số hợp lệ là online, là giá trị mặc định và offline.

Đặt giá trị thành offline nếu ứng dụng của bạn cần làm mới mã thông báo truy cập khi người dùng không có mặt trên trình duyệt. Đây là phương pháp làm mới mã truy cập được mô tả ở phần sau trong tài liệu này. Giá trị này hướng dẫn máy chủ ủy quyền của Google trả về một mã làm mới mã truy cập cho lần đầu tiên ứng dụng của bạn trao đổi mã ủy quyền cho mã thông báo.

state Nên

Chỉ định mọi giá trị chuỗi mà ứng dụng dùng để duy trì trạng thái giữa yêu cầu ủy quyền của bạn và phản hồi của máy chủ ủy quyền. Máy chủ trả về giá trị chính xác mà bạn gửi dưới dạng một cặp name=value trong thành phần truy vấn URL (?) của redirect_uri sau khi người dùng đồng ý hoặc từ chối yêu cầu truy cập của ứng dụng.

Bạn có thể sử dụng thông số này cho nhiều 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 nonces và giảm thiểu hành vi giả mạo yêu cầu trên nhiều trang web. Vì redirect_uri của bạn có thể được đoán ra, nên việc sử dụng giá trị state có thể làm tăng mức độ chắc chắn của bạn rằng kết nối đến là kết quả của một yêu cầu xác thực. Nếu bạn tạo một chuỗi ngẫu nhiên hoặc mã hóa giá trị băm của cookie hoặc giá trị khác thu thập trạng thái của ứng dụng, thì bạn có thể xác thực phản hồi để đảm bảo rằng yêu cầu và phản hồi bắt nguồn trong cùng một trình duyệt, qua đó bảo vệ bạn khỏi các cuộc tấn công như giả mạo yêu cầu trên nhiều trang web. Hãy xem tài liệu về OpenID Connect để xem ví dụ về cách tạo và xác nhận mã thông báo state.

include_granted_scopes Tùy chọn

Cho phép các ứng dụng dùng thông tin ủy 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 thông số này là true và yêu cầu ủy quyền được cấp, thì mã truy cập mới cũng sẽ đề cập đến mọi phạm vi mà người dùng trước đây đã cấp quyền truy cập vào ứng dụng. Hãy xem phần ủy quyền gia hạn để biết ví dụ.

login_hint Tùy chọn

Nếu biết ứng dụng nào đang cố gắng xác thực, ứng dụng của bạn có thể sử dụng thông 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 giản hóa 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 thích hợp.

Đặt giá trị thông số thành địa chỉ email hoặc giá trị nhận dạng sub, tương đương với mã nhận dạng Google của người dùng.

prompt Tùy chọn

Danh sách lời nhắc có phân biệt chữ hoa chữ thường và được phân tách bằng dấu cách để 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 vào 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 lại sự đồng ý để biết thêm thông tin.

Các giá trị có thể là:

none Không hiển thị bất kỳ màn hình xác thực hoặc màn hình đồng ý nào. Không được chỉ định cùng với các giá trị khác.
consent Nhắc người dùng đồng ý.
select_account Nhắc người dùng chọn tài khoản.

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à ủy 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 trước tiên. Trong trường hợp ủy quyền gia tăng, bước này cũng xảy ra khi ứng dụng của bạn lần đầu tiên cần truy cập vào các tài nguyên bổ sung mà ứng dụng chưa có quyền truy cập.

PHP

  1. Tạo URL để yêu cầu quyền truy cập từ máy chủ OAuth 2.0 của Google:
    $auth_url = $client->createAuthUrl();
  2. 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 ủy quyền bằng cách sử dụng khung ứng dụng web Flask:

return flask.redirect(authorization_url)

Ruby

  1. Tạo URL để yêu cầu quyền truy cập từ máy chủ OAuth 2.0 của Google:
    auth_uri = auth_client.authorization_uri.to_s
  2. Chuyển hướng người dùng tới auth_uri.

Node.js

  1. Sử dụng URL đã tạo authorizationUrl từ phương thức Bước 1 generateAuthUrl để yêu cầu quyền truy cập từ máy chủ OAuth 2.0 của Google.
  2. Chuyển hướng người dùng tới authorizationUrl.
    res.writeHead(301, { "Location": authorizationUrl });

HTTP/REST

Sample redirect to Google's authorization server

An example URL is shown below, with line breaks and spaces for readability.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.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

Sau 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 sẽ xác thực người dùng và nhận được sự đồng ý của người dùng để ứng dụng của bạn truy cập các phạm vi đã yêu cầu. Phản hồi sẽ được gửi trở lại ứng dụng của bạn bằng cách sử dụ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 có cấp cho ứng dụng của bạn quyền truy cập đã 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 đồng ý, trong đó hiển thị tên ứng dụng 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 ủy quyền của người dùng và bản tóm tắt các phạm vi quyền 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 theo yêu cầu của bạn hoặc từ chối yêu cầu.

Ứng dụng của bạn không cần làm gì trong giai đoạn này vì đang chờ phản hồi của máy chủ OAuth 2.0 của Google cho biết liệu có cấp quyền truy cập nào không. Phản hồi đó sẽ được giải thích trong bước sau.

Lỗi

Các yêu cầu đến điểm cuối ủy quyền OAuth 2.0 của Google có thể hiển thị các thông báo lỗi mà người dùng thấy được thay vì các quy trình xác thực và ủy quyền dự kiến. Bên dưới là các mã lỗi phổ biến và cách giải quyết được đề xuất.

admin_policy_enforced

Tài khoản Google không thể ủy quyền một hoặc nhiều phạm vi được yêu cầu do các chính sách của quản trị viên Google Workspace của họ. Hãy xem bài viết trợ giúp dành cho Quản trị viên Google Workspace Kiểm soát những nội dung &amp của bên thứ ba; các ứng dụng nội bộ 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ả cá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 vào mã ứng dụng OAuth của bạn.

disallowed_useragent

Điểm cuối ủy quyền được hiển thị bên trong tác nhân người dùng đã nhúng theo Chính sách OAuth 2.0 của Google.

Android

Nhà phát triển Android có thể nhận được thông báo lỗi này khi mở yêu cầu ủy quyền trong android.webkit.WebView. Thay vào đó, nhà phát triển nên sử dụng các thư viện Android như Đăng nhập bằng Google cho Android hoặc AppAuth cho Android.

Các nhà phát triển web có thể gặp lỗi này khi ứng dụng Android mở một đường liên kết 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 ủy quyền OAuth 2.0 của Google trên trang web của bạn. Nhà phát triển nên cho phép mở đường liên kết chung 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 trong ứng dụng Android hoặc ứng dụng trình duyệt mặc định). Thư viện Các thẻ tùy chỉnh Android cũng là một tùy chọn được hỗ trợ.

iOS

Các nhà phát triển iOS và macOS có thể gặp lỗi này khi mở các yêu cầu ủy quyền trong WKWebView. Thay vào đó, nhà phát triển nên sử dụng các thư viện dành cho iOS như Đăng nhập bằng Google dành cho iOS hoặc AppAuth for iOS của OpenID Foundation.

Các nhà phát triển web có thể gặp lỗi này khi ứng dụng iOS hoặc macOS mở một đường liên kết 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 ủy quyền OAuth 2.0 của Google trên trang web của bạn. Nhà phát triển nên cho phép mở các đường liên kết chung 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 tuỳ 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 hạn chế 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ề tùy 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 về Thiết lập màn hình đồng ý OAuth.

redirect_uri_mismatch

redirect_uri được chuyển trong yêu cầu ủy quyền không khớp với URI chuyển hướng được ủy quyền cho mã ứng dụng OAuth. Xem lại các URI chuyển hướng được ủy quyền trong Google API Console Credentials page.

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 quyền truy cập của ứng dụng bằng cách dùng URL được chỉ định trong yêu cầu.

Nếu người dùng chấp thuận yêu cầu truy cập, thì phản hồi sẽ chứa một mã ủy 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 một thông báo lỗi. Mã ủy 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ư minh họa dưới đây:

Phản hồi lỗi:

https://oauth2.example.com/auth?error=access_denied

Phản hồi mã ủy quyền:

https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7

Phản hồi của máy chủ OAuth 2.0 mẫu

Bạn có thể kiểm tra quy trình này bằng cách nhấp vào URL mẫu sau. URL này yêu cầu quyền chỉ có quyền đọc để xem siêu dữ liệu cho tệp trong Google Drive của bạn:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.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

Sau khi hoàn thành quy trình OAuth 2.0, bạn nên được chuyển hướng đến http://localhost/oauth2callback. Việc này có thể gây ra lỗi 404 NOT FOUND trừ khi máy cục bộ của bạn phân phát tệp tại địa chỉ đó. Bước tiếp theo sẽ cung cấp thêm thông tin chi tiết về thông tin được trả về trong URI khi người dùng được chuyển hướng trở lại ứng dụng của bạn.

Bước 5: Trao đổi mã ủy quyền để làm mới và truy cập mã thông báo

Sau khi máy chủ web nhận được mã ủy quyền, máy chủ có thể trao đổi mã ủy quyền để lấy mã truy cập.

PHP

Để trao đổi mã ủy quyền cho mã truy cập, hãy sử dụng phương thức authenticate:

$client->authenticate($_GET['code']);

Bạn có thể truy xuất mã thông báo truy cập bằng phương thức getAccessToken:

$access_token = $client->getAccessToken();

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ủ ủy quyền. Sau đó, hãy sử dụng phương thức flow.fetch_token để trao đổi mã ủy quyền trong phản hồi đó cho 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/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,
    'scopes': credentials.scopes}

Ruby

Để trao đổi mã ủy quyền cho mã truy cập, hãy sử dụng phương thức fetch_access_token!:

auth_client.code = auth_code
auth_client.fetch_access_token!

Node.js

Để trao đổi mã ủy quyền cho 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.
if (req.url.startsWith('/oauth2callback')) {
  // Handle the OAuth 2.0 server response
  let q = url.parse(req.url, true).query;

  // Get access and refresh tokens (if access_type is offline)
  let { tokens } = await oauth2Client.getToken(q.code);
  oauth2Client.setCredentials(tokens);
}

HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

Để trao đổi mã ủy quyền cho mã truy cập, hãy gọi điểm cuối https://oauth2.googleapis.com/token và đặt các thông số sau:

Trường
client_id Mã ứng dụng thu được từ API Console Credentials page.
client_secret Mật khẩu ứng dụng khách đã lấy từ API Console Credentials page.
code Mã ủy quyền trả về từ yêu cầu ban đầu.
grant_type Như đã xác định trong quy cách OAuth 2.0, bạn phải đặt giá trị của trường này là 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 API Console Credentials page cho client_id đã cho.

Đoạn mã sau đây hiển thị một yêu cầu mẫu:

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 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 thông số access_type thành offline trong yêu cầu ban đầu của máy chủ ủy 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 để ủy quyền 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ể sử dụng để lấy mã truy cập mới. Mã làm mới sẽ có hiệu lực cho đến khi người dùng thu hồi quyền truy cập. 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 thông số access_type thành offline trong yêu cầu ban đầu đến máy chủ ủy quyền của Google.
scope Phạm vi truy cập do access_token cấp được biểu thị dưới dạng danh sách các chuỗi được phân tách bằng dấu cách và phân biệt chữ hoa chữ thường.
token_type Loại mã thông báo được trả về. Lúc này, giá trị của trường này luôn được đặt thành Bearer.

Đoạn mã sau đây cho thấy một phản hồi mẫu:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

Gọi API Google

PHP

Sử dụng mã truy cập để gọi API của Google bằng cách hoàn thành các bước sau:

  1. Nếu bạn cần áp dụng mã truy cập cho đối tượng Google_Client mới (ví dụ: nếu bạn lưu trữ mã truy cập trong một phiên hoạt động của người dùng), hãy sử dụng phương thức setAccessToken:
    $client->setAccessToken($access_token);
  2. Tạo đối tượng dịch vụ cho API mà bạn muốn gọi. Bạn tạo đối tượng dịch vụ bằng cách cung cấp một đối tượng Google_Client được ủy quyền cho hàm dựng cho API mà bạn muốn gọi. Ví dụ: để gọi API Drive:
    $drive = new Google_Service_Drive($client);
  3. Gửi yêu cầu tới dịch vụ API bằng giao diện do đối tượng dịch vụ cung cấp. Ví dụ: để liệt kê các tệp trong Google Drive của người dùng đã xác thực:
    $files = $drive->files->listFiles(array())->getItems();

Python

Sau khi nhận được mã truy cập, ứng dụng của bạn có thể sử dụng mã đó để ủy quyền 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 đăng nhập ủy 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 đó để tạo các yêu cầu API được ủy quyền.

  1. Tạo đối tượng dịch vụ cho API mà bạn muốn gọi. Bạn tạo đối tượng dịch vụ bằng cách gọi phương thức build của thư viện googleapiclient.discovery bằ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 2 của API Drive:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. Gửi yêu cầu tới dịch vụ API bằng giao diện do đối tượng dịch vụ cung cấp. Ví dụ: để liệt kê các tệp trong Google Drive của người dùng đã xác thực:
    files = drive.files().list().execute()

Ruby

Hãy sử dụng đối tượng auth_client để gọi các API của Google bằng cách hoàn thành các bước sau:

  1. Tạo đối tượng dịch vụ cho API mà bạn muốn gọi. Ví dụ: để gọi phiên bản 2 của API Drive:
    drive = Google::Apis::DriveV2::DriveService.new
  2. Đặt thông tin xác thực cho dịch vụ này:
    drive.authorization = auth_client
  3. Gửi yêu cầu tới dịch vụ API bằng giao diện do đối tượng dịch vụ cung cấp. Ví dụ: để liệt kê các tệp trong Google Drive của người dùng đã xác thực:
    files = drive.list_files

Ngoài ra, bạn có thể cung cấp ủy quyền cho từng phương thức bằng cách cung cấp tham số options cho một phương thức:

files = drive.list_files(options: { authorization: auth_client })

Node.js

Sau khi lấy mã truy cập và đặt mã đó vào đối tượng OAuth2, hãy dùng đối tượng này để gọi API của Google. Ứng dụng của bạn có thể dùng mã đó để ủy quyền 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 đối tượng dịch vụ cho API mà bạn muốn gọi.

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 (Ngôn ngữ đánh dấu xác nhận bảo mật)

Sau khi ứng dụng của bạn nhận được mã truy cập, bạn có thể sử dụng mã đó để gọi điện đến API 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 quyền truy cập mà API yêu cầu đã cấp. Để làm điều này, hãy đưa mã truy cập vào yêu cầu API bằng cách thêm thông số truy vấn access_token hoặc tiêu đề Authorization tiêu đề HTTP Bearer. Khi có thể, bạn nên dùng tiêu đề HTTP vì các chuỗi truy vấn có xu hướng xuất hiện trong nhật ký máy chủ. Trong hầu hết 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 Google (ví dụ: khi gọi API Drive Files).

Bạn có thể dùng thử tất cả API của Google và xem phạm vi của các API này tại OAuth 2.0 Playground.

Ví dụ về HTTP GET

Lệnh gọi đến điểm cuối drive.files (API Drive Drive) bằng cách sử dụng tiêu đề HTTP Authorization: Bearer có thể có dạng như sau. Xin lưu ý rằng bạn cần chỉ định mã truy cập của riêng mình:

GET /drive/v2/files 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 cách sử dụng thông số chuỗi truy vấn access_token:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

Ví dụ về curl

Bạn có thể kiểm tra các lệnh này bằng ứng dụng dòng lệnh curl. Sau đây là ví dụ về cách sử dụng tùy chọn tiêu đề HTTP (ưu tiên):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

Hoặc tùy chọn tham số chuỗi truy vấn:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

Ví dụ đầy đủ

Ví dụ sau đây sẽ in danh sách các tệp theo định dạng JSON trong Google Drive của người dùng sau khi người dùng xác thực và đồng ý cho phép ứng dụng truy cập vào siêu dữ liệu Drive của người dùng đó.

PHP

Để chạy ví dụ này:

  1. 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.
  2. Tạo thư mục mới và thay đổi thư mục đó. Ví dụ:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Cài đặt Thư viện ứng dụng API của Google cho PHP bằng Composer:
    composer require google/apiclient:^2.0
  4. Tạo các tệp index.phpoauth2callback.php có nội dung bên dưới.
  5. Hãy chạy ví dụ này với một máy chủ web được định cấu hình để phân phát PHP. Nếu sử dụng PHP 5.4 trở lên, bạn có thể sử dụng máy chủ web thử nghiệm tích hợp 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_secrets.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google_Service_Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $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();
$client->setAuthConfigFile('client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

if (! isset($_GET['code'])) {
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  $client->authenticate($_GET['code']);
  $_SESSION['access_token'] = $client->getAccessToken();
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

Python

Ví dụ này sử dụng khung Flask. Ứng dụng này chạy một ứng dụng web tại http://localhost:8080 cho phép bạn kiểm tra quy trình OAuth 2.0. Nếu truy cập vào URL đó, bạn sẽ thấy 4 đường liên kết:

  • Thử nghiệm yêu cầu API: Đường liên kết này trỏ đến một trang cố thực hiện yêu cầu API mẫu. Nếu cần thiết, quy trình này sẽ bắt đầu quy trình ủy 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 xác thực: Đường liên kết này trỏ đến một trang cố gắng đưa người dùng đến thông qua quy trình ủy quyền. Ứng dụng này yêu cầu quyền thay mặt cho người dùng gửi yêu cầu API được ủy quyền.
  • Thu hồi thông tin đăng nhập hiện tại: Đường liên kết này trỏ đến một trang thu hồi quyền mà người dùng đã cấp cho ứng dụng.
  • Xóa thông tin xác thực của phiên hoạt động bình luận: Đường liên kết này sẽ xóa thông tin đăng nhập ủy quyền được lưu trữ trong phiên Bình đó. Điều này cho phép bạn thấy đ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 yêu cầu API trong một phiên mới. Thẻ 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 quyền đã cấp cho ứng dụng của bạn và ứng dụng đó vẫn cố gắng cấp phép cho yêu cầu bằng mã thông báo truy cập bị thu hồi.
# -*- 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"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.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('/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'])

  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)


@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.')

  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,
          'scopes': credentials.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="/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'

  # 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 'google/apis/drive_v2'
require 'google/api_client/client_secrets'
require 'json'
require 'sinatra'

enable :sessions
set :session_secret, 'setme'

get '/' do
  unless session.has_key?(:credentials)
    redirect to('/oauth2callback')
  end
  client_opts = JSON.parse(session[:credentials])
  auth_client = Signet::OAuth2::Client.new(client_opts)
  drive = Google::Apis::DriveV2::DriveService.new
  files = drive.list_files(options: { authorization: auth_client })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  client_secrets = Google::APIClient::ClientSecrets.load
  auth_client = client_secrets.to_authorization
  auth_client.update!(
    :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly',
    :redirect_uri => url('/oauth2callback'))
  if request['code'] == nil
    auth_uri = auth_client.authorization_uri.to_s
    redirect to(auth_uri)
  else
    auth_client.code = request['code']
    auth_client.fetch_access_token!
    auth_client.client_secret = nil
    session[:credentials] = auth_client.to_json
    redirect to('/')
  end
end

Node.js

Để chạy ví dụ này:

  1. 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.
  2. Đảm bảo bạn đã cài đặt LTS, bảo mật LTS hoặc bản phát hành hiện tại của Node.js.
  3. Tạo thư mục mới và thay đổi thư mục đó. Ví dụ:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Install the Google API Client Library for Node.js using npm:
    npm install googleapis
  5. Tạo tệp main.js có nội dung bên dưới.
  6. Chạy ví dụ:
    node .\main.js

main.js (.js)

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');

/**
 * 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 read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];

// Generate a url that asks permissions for the Drive activity 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
});

/* 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 server = http.createServer(async function (req, res) {
    // Example on redirecting user to Google's OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }

    // Receive the callback from Google's OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // 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 { // 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 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.');
          }
        });
      }
    }

    // Example on revoking a token
    if (req.url == '/revoke') {
      // 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();
    }
    res.end();
  }).listen(80);
}
main().catch(console.error);

HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

Ví dụ về Python này sử dụng khung Flask và thư viện Yêu cầu để chứng minh luồng web OAuth 2.0. Bạn nên sử dụng Thư viện ứng dụng Python cho API của Google 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__)

CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'
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/drive/v2/files'
    r = requests.get(req_uri, headers=headers)
    return r.text


@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}').format(CLIENT_ID, REDIRECT_URI, SCOPE)
    return flask.redirect(auth_uri)
  else:
    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'}
    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 những quy tắc xác thực sau đây để chuyển hướng URI nhằm 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ủ những quy tắc này. Xem RFC 3986 mục 3 để biết định nghĩa về miền, máy chủ, đường dẫn, truy vấn, lược đồ và thông tin người dùng, được đề cập ở bên dưới.

Các quy tắc xác thực
Lược đồ

URI chuyển hướng phải dùng lược đồ HTTPS, không phải HTTP thuần. Các URI của máy chủ cục bộ (bao gồm các URI địa chỉ IP của máy chủ cục bộ) không được áp dụng cho quy tắc này.

Máy chủ lưu trữ

Máy chủ không thể là địa chỉ IP thô. Địa chỉ IP máy chủ cục bộ được miễn khỏi quy tắc này.

Miền
  • Các TLD lưu trữ (Miền cấp cao nhất) phải thuộc danh sách hậu tố công khai.
  • Tên miền lưu trữ không được là “googleusercontent.com”.
  • URI chuyển hướng không được chứa các miền rút ngắn URL (ví dụ: goo.gl) trừ phi ứng dụng sở hữu miền này. 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ì URL chuyển hướng đó phải chứa “/google-callback/” trong đường dẫn của ứng dụng hoặc kết thúc bằng “/google-callback”.
  • Thông tin người dùng

    URI chuyển hướng không được chứa thành phần phụ thông tin người dùng.

    Đườ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à theo dõi thư mục), được biểu thị bằng “/..” hoặc “\..” hoặc mã hóa URL của các đường dẫn đó.

    Cụm từ tìm kiếm

    URI chuyển hướng không được chứa lệnh chuyển hướng mở.

    Mảnh

    URI chuyển hướng không được chứa thành phần mảnh.

    Ký tự URI chuyển hướng không được chứa một số ký tự nhất định, bao gồm:
    • Ký tự đại diện ('*')
    • Ký tự ASCII không thể in được
    • Mã hóa phần trăm không hợp lệ (mọi phần mã hóa phần trăm không tuân theo dạng mã hóa URL của dấu phần trăm, theo sau là hai chữ số thập lục phân)
    • Ký tự rỗng (một ký tự NULL được mã hóa, ví dụ: %00, %C0%80)

    Ủy quyền gia tăng

    Trong giao thức OAuth 2.0, ứng dụng của bạn yêu cầu ủy quyền truy cập vào các tài nguyên mà chúng tôi xác định theo phạm vi. Việc yêu cầu ủy quyền cho các tài nguyên tại thời điểm bạn cần sẽ được coi là phương pháp hay nhất cho trải nghiệm người dùng. Để bật tính năng này, máy chủ ủy quyền của Google sẽ hỗ trợ việc ủy 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 thiết và nếu người dùng cấp quyền cho phạm vi mới, sẽ trả về một mã ủy quyền có thể được đổi lấy mã thông báo chứa tất cả phạm vi mà người dùng đã cấp dự án.

    Ví dụ: một ứng dụng cho phép mọi người lấy mẫu bản nhạc và tạo danh sách nhạc kết hợp có thể cần rất ít tài nguyên tại thời điểm đăng nhập, và có thể sẽ không cần gì ngoài tên của người đang đăng nhập. Tuy nhiên, bạn phải có quyền truy cập vào Google Drive để lưu danh sách kết hợp hoàn chỉnh. Hầu hết mọi người sẽ cảm thấy tự nhiên nếu họ chỉ được yêu cầu cấp quyền truy cập vào Google Drive vào thời điểm thực sự cần ứng dụng.

    Trong trường hợp này, vào thời điểm đăng nhập, ứng dụng có thể yêu cầu phạm vi openidprofile để thực hiện việc đăng nhập cơ bản, sau đó yêu cầu phạm vi https://www.googleapis.com/auth/drive.file tại thời điểm yêu cầu đầu tiên lưu kết hợp.

    Để triển khai lệnh ủy quyền gia tăng, bạn phải hoàn thành quy trình bình thường để yêu cầu mã truy cập, nhưng hãy đảm bảo yêu cầu ủy quyền bao gồm các phạm vi đã cấp trước đó. Phương pháp này cho phép ứng dụng của bạn tránh 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 nhận được từ một ủy 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 mọi phạm vi được đưa vào sự ủy quyền kết hợp mới.
    • Khi bạn sử dụng mã làm mới cho lệnh ủy quyền kết hợp để lấy mã truy cập, mã truy cập này đại diện cho mã ủy quyền kết hợp và có thể dùng cho bất kỳ giá trị scope nào trong phản hồi.
    • Quy trình ủy quyền kết hợp bao gồm tất cả các phạm vi mà người dùng được cấp cho dự án API ngay cả khi các ứng dụng khác nhau yêu cầu cấp quyền. 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 dành cho máy tính của một ứng dụng, sau đó cấp một phạm vi khác cho ứng dụng đó thông qua ứng dụng dành cho thiết bị di động, thì lệnh ủy 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 lệnh ủy quyền kết hợp, quyền truy cập vào tất cả các phạm vi ủy 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ẫu mã dành riêng cho ngôn ngữ trong Bước 1: Thiết lập tham số ủy quyền và URL chuyển hướng HTTP/REST mẫu trong Bước 2: Chuyển hướng đến máy chủ OAuth 2.0 của Google đều sử dụng hình thức ủy quyền gia tăng. Các mã mẫu bên dưới cũng hiển thị mã mà bạn cần thêm để sử dụng tùy chọn ủy quyền gia tăng.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    Trong Python, hãy đặt đối số từ khóa include_granted_scopes thành true để đảm bảo rằng yêu cầu ủy quyền có các phạm vi đã cấp trước đó. Có thể include_granted_scopes sẽ không phải là đối số từ khóa chỉ 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 (Ngôn ngữ đánh dấu xác nhận bảo mật)

    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.file&
      redirect_uri=https%3A//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    Làm mới mã thông báo truy cập (truy cập ngoại tuyến)

    Mã thông báo truy cập sẽ hết hạn theo định kỳ và trở thành thông tin đăng nhập không hợp lệ cho yêu cầu API có liên quan. Bạn có thể làm mới mã truy cập mà không cần nhắc người dùng về quyền (bao gồm cả khi người dùng không hiện diện) nếu bạn đã yêu cầu quyền truy cập ngoại tuyến vào các phạm vi liên kết với mã đó.

    • Nếu bạn sử dụng Thư viện ứng dụng API của Google, đối tượng máy khách sẽ làm mới mã thông báo truy cập này, miễn là bạn định cấu hình đối tượng đó để truy cập khi không có mạng.
    • Nếu không sử dụng thư viện ứng dụng, bạn cần đặt tham số truy vấn HTTP access_type thành offline khi chuyển hướng người dùng đến máy chủ OAuth 2.0 của Google. Trong trường hợp đó, máy chủ ủy quyền của Google sẽ trả về mã làm mới khi bạn đổi mã ủy quyền để có mã truy cập. Sau đó, nếu mã truy cập hết hạn (hoặc bất cứ lúc nào khác), bạn có thể sử dụng mã làm mới để lấy mã truy cập mới.

    Yêu cầu quyền truy cập ngoại tuyến là yêu cầu bắt buộc đối với mọi ứng dụng cần truy cập vào API của Google khi người dùng không có mặt. Ví dụ: một ứng dụng thực hiện dịch vụ sao lưu hoặc thực hiện thao tác vào những thời điểm đã xác định trước cần phải làm mới mã truy cập của ứng dụng khi người dùng không có mặt. Kiểu truy cập mặc định được gọi là online.

    Các ứng dụng web, ứng dụng đã cài đặt và thiết bị phía máy chủ đều nhận được mã thông báo làm mới trong quá trình ủy quyền. Mã thông báo làm mới thường không được dùng trong các ứng dụng web (JavaScript) phía máy khách.

    PHP

    Nếu ứng dụng của bạn cần quyền truy cập khi không có mạng vào một API Google, hãy đặt loại quyền truy cập của ứng dụng API thành offline:

    $client->setAccessType("offline");

    Sau khi người dùng cấp quyền truy cập ngoại tuyến vào các phạm vi đã yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập API Google thay mặt cho người dùng khi người dùng không có kết nối mạng. Đối tượng máy khách sẽ làm mới mã truy cập nếu cần.

    Python

    Trong Python, hãy đặt đối số từ khóa access_type thành offline để đảm bảo rằng bạn sẽ có thể làm mới mã truy cập mà không phải nhắc lại người dùng cấp quyền. Có thể access_type sẽ không phải là đối số từ khóa chỉ mà bạn đặt, như minh họa 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 ngoại tuyến vào các phạm vi đã yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập API Google thay mặt cho người dùng khi người dùng không có kết nối mạng. Đối tượng máy 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 khi không có mạng vào một API 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 ngoại tuyến vào các phạm vi đã yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập API Google thay mặt cho người dùng khi người dùng không có kết nối mạng. Đối tượng máy 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 khi không có mạng vào một API 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 ngoại tuyến vào các phạm vi đã yêu cầu, bạn có thể tiếp tục sử dụng ứng dụng API để truy cập API Google thay mặt cho người dùng khi người dùng không có kết nối mạng. Đối tượng máy khách sẽ làm mới mã truy cập nếu cần.

    Mã thông báo truy cập sẽ hết hạn. Thư viện này sẽ tự động dùng mã làm mới để lấy mã truy cập mới nếu mã đó 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ỉ diễn ra trong lần ủy quyền đầu tiên và bạn phải đặ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 quyền yêu cầu lại mà không cần đặt 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 phải cho phép lại ứng dụng để nhận mã làm mới.

    Để đặt refresh_token sau, bạn có thể sử dụng phương thức setCredentials:

    oauth2Client.setCredentials({
      refresh_token: `STORED_REFRESH_TOKEN`
    });
    

    Sau khi máy khách có mã làm mới, mã truy cập sẽ được lấy tự động và làm mới trong lệnh gọi tiếp theo tới API.

    HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

    Để làm mới mã truy cập, ứng dụng của bạn sẽ gửi một yêu cầu POST HTTPS đến máy chủ ủy quyền của Google (https://oauth2.googleapis.com/token) trong đó có các thông số sau:

    Trường
    client_id Mã ứng dụng được lấy từ API Console.
    client_secret Mật khẩu ứng dụng khách lấy từ API Console.
    grant_type Như đã xác định trong quy cách OAuth 2.0, bạn phải đặt giá trị của trường này là refresh_token.
    refresh_token Mã làm mới sẽ trả về từ sàn giao dịch mã ủy quyền.

    Đoạn mã sau đây hiển thị một yêu cầu mẫu:

    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

    Miễn là người dùng chưa thu hồi quyền truy cập được cấp cho ứng dụng, thì máy chủ mã thông báo sẽ trả về một đối tượng JSON chứa mã truy cập mới. Đoạn mã sau đây cho thấy một phản hồi mẫu:

    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
      "token_type": "Bearer"
    }

    Xin lưu ý rằng sẽ có giới hạn về số lượng mã thông báo làm mới sẽ được phát hành; một giới hạn cho mỗi tổ hợp khách hàng/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ả khách hàng. Bạn nên lưu các mã thông báo làm mới trong bộ nhớ dài hạn và tiếp tục sử dụng các mã thông báo đó, miễn là các mã này vẫn hợp lệ. Nếu ứng dụng của bạn yêu cầu quá nhiều mã làm mới, ứng dụng có thể gặp phải các giới hạn này. Trong trường hợp đó, các mã thông báo 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 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 Xóa quyền truy cập vào trang web hoặc ứng dụng của trang web bên thứ ba và amp; các ứng dụng có quyền truy cập vào tài khoản của bạn tài liệu hỗ trợ để 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 theo phương thức lập trình. Tính năng thu hồi có lập trình đóng vai trò quan trọng trong các trường hợp người dùng hủy đăng ký, xoá một ứng dụng hoặc các tài nguyên API mà một ứng dụng yêu cầu đã thay đổi đáng kể. Nói cách khác, quy trình xoá có thể chứa một yêu cầu API để đảm bảo những quyền trước đây đã cấp cho ứng dụng này 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 bằng cách lập trình, hãy gửi yêu cầu tới https://oauth2.googleapis.com/revoke, trong đó bao gồm mã thông báo dưới dạng thông 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 bằng cách lập trình, hãy thực hiện 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ã này có thể là mã truy cập hoặc mã làm mới. Nếu mã này là mã truy cập và có mã mới, thì mã làm mới cũng sẽ bị thu hồi.

    Nếu quá trình thu hồi được xử lý thành công, thì mã trạng thái của phản hồi sẽ là 200. Đối với điều kiện lỗi, mã trạng thái 400 đượ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 thực hiện yêu cầu POST HTTPS đế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();
    

    Thông số mã thông báo có thể là mã truy cập hoặc mã làm mới. Nếu mã này là mã truy cập và có mã mới, thì mã làm mới cũng sẽ bị thu hồi.

    Nếu quá trình thu hồi được xử lý thành công, thì mã trạng thái của phản hồi sẽ là 200. Đối với điều kiện lỗi, mã trạng thái 400 được trả về cùng với mã lỗi.

    HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

    Để 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ẽ yêu cầu https://oauth2.googleapis.com/revoke và đưa mã thông báo làm thông số:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    Mã này có thể là mã truy cập hoặc mã làm mới. Nếu mã này là mã truy cập và có mã mới, thì mã làm mới cũng sẽ bị thu hồi.

    Nếu quá trình 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 điều kiện lỗi, mã trạng thái HTTP 400 sẽ được trả về cùng với mã lỗi.