Sử dụng mô hình mã thông báo

Thư viện JavaScript google.accounts.oauth2 giúp bạn nhắc người dùng đồng ý và lấy mã truy cập để làm việc với dữ liệu người dùng. Tính năng này dựa trên quy trình cấp quyền ngầm ẩn của OAuth 2.0 và được thiết kế để cho phép bạn gọi trực tiếp API của Google bằng REST và CORS hoặc dùng thư viện ứng dụng API của Google cho JavaScript (còn gọi là gapi.client) để truy cập đơn giản và linh hoạt vào các API phức tạp hơn.

Trước khi truy cập vào dữ liệu người dùng được bảo vệ từ một trình duyệt, người dùng trên trang web của bạn sẽ kích hoạt trình chọn tài khoản dựa trên web của Google, đăng nhập và quy trình đồng ý, cuối cùng là sự cố máy chủ OAuth của Google và trả về mã truy cập cho ứng dụng web của bạn.

Trong mô hình uỷ quyền dựa trên mã thông báo, bạn không cần lưu trữ mã làm mới cho mỗi người dùng trên máy chủ phụ trợ.

Bạn nên làm theo phương pháp được nêu ở đây thay vì các kỹ thuật được đề cập trong hướng dẫn OAuth 2.0 cho ứng dụng web phía máy khách cũ.

Thiết lập

Tìm hoặc tạo mã ứng dụng khách bằng cách làm theo các bước được mô tả trong hướng dẫn Nhận mã ứng dụng khách Google API. Tiếp theo, hãy thêm thư viện ứng dụng vào các trang trên trang web của bạn sẽ gọi API của Google. Cuối cùng, hãy khởi chạy ứng dụng mã thông báo. Thông thường, việc này được thực hiện trong trình xử lý onload của thư viện ứng dụng.

Khởi chạy ứng dụng mã thông báo

Gọi initTokenClient() để khởi chạy một ứng dụng mã thông báo mới bằng mã ứng dụng khách của ứng dụng web. Nếu muốn, bạn có thể đưa vào danh sách một hoặc nhiều phạm vi mà người dùng cần truy cập:

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (response) => {
    ...
  },
});

Kích hoạt quy trình mã thông báo OAuth 2.0

Sử dụng phương thức requestAccessToken() để kích hoạt luồng trải nghiệm người dùng của mã thông báo và lấy mã truy cập. Google sẽ nhắc người dùng:

  • Chọn tài khoản của họ,
  • đăng nhập vào Tài khoản Google nếu chưa đăng nhập,
  • cho phép ứng dụng web của bạn truy cập vào từng phạm vi được yêu cầu.

Cử chỉ của người dùng sẽ kích hoạt luồng mã thông báo: <button onclick="client.requestAccessToken();">Authorize me</button>

Sau đó, Google sẽ trả về một TokenResponse chứa mã truy cập và danh sách các phạm vi mà người dùng đã cấp quyền truy cập hoặc lỗi cho trình xử lý gọi lại.

Người dùng có thể đóng trình chọn tài khoản hoặc cửa sổ đăng nhập. Trong trường hợp đó, chức năng gọi lại của bạn sẽ không được gọi.

Bạn chỉ nên triển khai thiết kế và trải nghiệm người dùng cho ứng dụng sau khi xem xét kỹ Chính sách OAuth 2.0 của Google. Các chính sách này đề cập đến hoạt động ở nhiều phạm vi, thời điểm và cách thức xử lý sự đồng ý của người dùng, v.v.

Uỷ quyền gia tăng là một phương pháp thiết kế ứng dụng và chính sách dùng để yêu cầu quyền truy cập vào tài nguyên, chỉ dùng phạm vi khi cần thay vì trả trước và tất cả cùng một lúc. Người dùng có thể phê duyệt hoặc từ chối chia sẻ tài nguyên riêng lẻ mà ứng dụng của bạn yêu cầu, quyền này được gọi là quyền chi tiết.

Trong quá trình này, Google sẽ nhắc người dùng đồng ý, liệt kê từng phạm vi được yêu cầu, người dùng chọn các tài nguyên sẽ chia sẻ với ứng dụng của bạn và cuối cùng, Google sẽ gọi hàm callback để trả về một mã truy cập và phạm vi người dùng đã phê duyệt. Sau đó, ứng dụng của bạn sẽ xử lý nhiều kết quả có thể một cách an toàn với các quyền chi tiết.

Uỷ quyền gia tăng

Đối với các ứng dụng web, 2 tình huống cấp cao sau đây minh hoạ việc uỷ quyền gia tăng bằng cách sử dụng:

  • Một ứng dụng Ajax một trang, thường sử dụng XMLHttpRequest với quyền truy cập động vào các tài nguyên.
  • Nhiều trang web, tài nguyên được tách riêng và quản lý theo từng trang.

2 tình huống này được trình bày để minh hoạ các phương pháp và cân nhắc về thiết kế. Tuy nhiên, đây không phải là các đề xuất toàn diện về cách tạo sự đồng ý cho ứng dụng của bạn. Các ứng dụng thực tế có thể sử dụng một biến thể hoặc kết hợp các kỹ thuật này.

Ajax

Thêm tính năng hỗ trợ cho việc uỷ quyền gia tăng cho ứng dụng của bạn bằng cách thực hiện nhiều lệnh gọi đến requestAccessToken() và dùng tham số scope của đối tượng OverridableTokenClientConfig để yêu cầu từng phạm vi tại thời điểm cần thiết và chỉ khi cần. Trong ví dụ này, các tài nguyên sẽ được yêu cầu và chỉ hiển thị sau khi cử chỉ của người dùng mở rộng phần nội dung đã thu gọn.

Ứng dụng Ajax
Khởi động ứng dụng mã thông báo khi tải trang:
        const client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_GOOGLE_CLIENT_ID',
          callback: "onTokenResponse",
        });
      
Yêu cầu sự đồng ý và lấy mã truy cập thông qua các cử chỉ của người dùng, nhấp vào dấu "+" để mở:

Tài liệu cần đọc

Hiện các tài liệu gần đây

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/documents.readonly'
             })
           );
        

Sự kiện sắp tới

Hiển thị thông tin lịch

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/calendar.readonly'
             })
           );
        

Hiển thị ảnh

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/photoslibrary.readonly'
             })
           );
        

Mỗi lệnh gọi đến requestAccessToken sẽ kích hoạt một thời điểm đồng ý của người dùng, ứng dụng của bạn sẽ chỉ có quyền truy cập vào các tài nguyên theo yêu cầu của phần người dùng chọn mở rộng, do đó hạn chế việc chia sẻ tài nguyên thông qua lựa chọn của người dùng.

Nhiều trang web

Khi thiết kế quy trình uỷ quyền gia tăng, nhiều trang sẽ được dùng để chỉ yêu cầu(các) phạm vi cần thiết để tải một trang, qua đó giảm sự phức tạp và không cần thực hiện nhiều lệnh gọi để có được sự đồng ý của người dùng và truy xuất mã truy cập.

Ứng dụng nhiều trang
Trang web
Trang 1. Tài liệu cần đọc
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/documents.readonly',
  });
  client.requestAccessToken();
          
Trang 2. Sự kiện sắp tới
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/calendar.readonly',
  });
  client.requestAccessToken();
          
Trang 3. Băng chuyền ảnh
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/photoslibrary.readonly',
  });
  client.requestAccessToken();
          

Mỗi trang yêu cầu phạm vi cần thiết và nhận mã truy cập bằng cách gọi initTokenClient()requestAccessToken() tại thời điểm tải. Trong trường hợp này, các trang web riêng lẻ được dùng để phân tách rõ ràng chức năng của người dùng và tài nguyên theo phạm vi. Trong tình huống thực tế, các trang riêng lẻ có thể yêu cầu nhiều phạm vi liên quan.

Quyền chi tiết

Các quyền chi tiết được xử lý theo cách tương tự trong mọi trường hợp. Sau khi requestAccessToken() gọi hàm callback và mã truy cập được trả về, hãy kiểm tra để đảm bảo rằng người dùng đã phê duyệt các phạm vi được yêu cầu bằng cách sử dụng hasGrantedAllScopes() hoặc hasGrantedAnyScope(). Ví dụ:

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly \
          https://www.googleapis.com/auth/documents.readonly \
          https://www.googleapis.com/auth/photoslibrary.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      if (google.accounts.oauth2.hasGrantedAnyScope(tokenResponse,
          'https://www.googleapis.com/auth/photoslibrary.readonly')) {
        // Look at pictures
        ...
      }
      if (google.accounts.oauth2.hasGrantedAllScopes(tokenResponse,
          'https://www.googleapis.com/auth/calendar.readonly',
          'https://www.googleapis.com/auth/documents.readonly')) {
        // Meeting planning and review documents
        ...
      }
    }
  },
});

Mọi khoản trợ cấp được chấp nhận trước đó từ các phiên hoặc yêu cầu trước đó cũng sẽ được đưa vào phản hồi. Hồ sơ về sự đồng ý của người dùng được lưu giữ theo từng người dùng và Mã ứng dụng khách, đồng thời duy trì qua nhiều lệnh gọi đến initTokenClient() hoặc requestAccessToken(). Theo mặc định, bạn chỉ cần lấy sự đồng ý của người dùng khi người dùng truy cập vào trang web của bạn lần đầu tiên và yêu cầu phạm vi mới. Tuy nhiên, bạn có thể yêu cầu sự đồng ý này trong mỗi lần tải trang bằng cách sử dụng prompt=consent trong các đối tượng cấu hình Mã thông báo.

Làm việc với mã thông báo

Trong mô hình Mã thông báo, hệ điều hành hoặc trình duyệt không lưu trữ mã truy cập. Thay vào đó, mã thông báo mới sẽ được lấy lần đầu tiên tại thời điểm tải trang, hoặc sau đó kích hoạt lệnh gọi đến requestAccessToken() thông qua một cử chỉ của người dùng, chẳng hạn như nhấn nút.

Sử dụng REST và CORS với các API của Google

Bạn có thể dùng mã truy cập để gửi các yêu cầu đã xác thực đến các API của Google bằng cách sử dụng REST và CORS. Điều này cho phép người dùng đăng nhập, đồng ý, Google sẽ cấp mã truy cập và trang web của bạn để hoạt động với dữ liệu của người dùng.

Trong ví dụ này, hãy xem các sự kiện sắp tới trên lịch của người dùng đã đăng nhập bằng cách sử dụng mã truy cập do tokenRequest() trả về:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
xhr.setRequestHeader('Authorization', 'Bearer ' + tokenResponse.access_token);
xhr.send();

Xem Cách sử dụng CORS để truy cập API Google để biết thêm.

Phần tiếp theo trình bày cách tích hợp dễ dàng với các API phức tạp hơn.

Làm việc với thư viện JavaScript API của Google

Ứng dụng mã thông báo hoạt động với Thư viện ứng dụng API của Google cho JavaScript Hãy xem đoạn mã dưới đây.

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

Thời hạn của mã thông báo

Theo thiết kế, mã truy cập có thời gian tồn tại ngắn. Nếu mã truy cập hết hạn trước khi phiên của người dùng kết thúc, hãy lấy mã thông báo mới bằng cách gọi requestAccessToken() từ một sự kiện do người dùng thực hiện, chẳng hạn như thao tác nhấn nút.

Gọi phương thức google.accounts.oauth2.revoke để xoá sự đồng ý của người dùng và truy cập vào các tài nguyên cho tất cả phạm vi đã cấp cho ứng dụng của bạn. Bạn phải có một mã truy cập hợp lệ để thu hồi quyền này:

google.accounts.oauth2.revoke('414a76cb127a7ece7ee4bf287602ca2b56f8fcbf7fcecc2cd4e0509268120bd7', done => {
    console.log(done);
    console.log(done.successful);
    console.log(done.error);
    console.log(done.error_description);
  });