Đăng nhập bằng Google dành cho các ứng dụng phía máy chủ

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Để thay mặt người dùng sử dụng các dịch vụ của Google khi họ ở chế độ ngoại tuyến, bạn phải sử dụng luồng kết hợp phía máy chủ, trong đó người dùng ủy quyền cho ứng dụng của bạn ở phía máy khách bằng cách sử dụng ứng dụng API JavaScript và bạn sẽ gửi mã ủy quyền một lần đặc biệt đến máy chủ của mình. Máy chủ sẽ trao đổi mã dùng một lần này để lấy mã truy cập và làm mới mã thông báo từ Google cho máy chủ để thực hiện các lệnh gọi API riêng. Bạn có thể thực hiện việc này khi người dùng không có kết nối mạng. Luồng mã một lần này có các lợi thế về bảo mật so với cả luồng đơn thuần từ phía máy chủ và việc gửi mã thông báo truy cập đến máy chủ của bạn.

Quy trình đăng nhập để lấy mã truy cập cho ứng dụng phía máy chủ của bạn được minh hoạ bên dưới.

Mã một lần có một số ưu điểm về bảo mật. Với mã, Google cung cấp mã thông báo trực tiếp cho máy chủ của bạn mà không cần bất kỳ trung gian nào. Chúng tôi khuyên bạn không nên làm rò rỉ mã nhưng rất khó sử dụng nếu không có mật khẩu ứng dụng khách. Hãy giữ bí mật thông tin khách hàng của bạn!

Triển khai luồng mã một lần

Nút Đăng nhập bằng Google cung cấp cả mã truy cậpmã uỷ quyền. Mã này là mã một lần mà máy chủ của bạn có thể trao đổi với máy chủ của Google để lấy mã truy cập.

Mã mẫu sau đây minh hoạ cách thực hiện luồng mã một lần.

Để xác thực tính năng đăng nhập bằng Google bằng quy trình mã một lần, bạn cần phải:

Bước 1: Tạo một mã ứng dụng khách và mật khẩu ứng dụng khách

Để tạo một mã ứng dụng khách và mật khẩu ứng dụng khách, hãy tạo một dự án Google API Console, thiết lập một mã ứng dụng khách OAuth và đăng ký mã nguồn JavaScript của bạn:

  1. Chuyển đến Google API Console.

  2. Từ trình đơn thả xuống của dự án, hãy chọn một dự án hiện có hoặc tạo một dự án mới bằng cách chọn Tạo dự án mới.

  3. Trong thanh bên trong phần "API & Services", hãy chọn Thông tin xác thực, rồi nhấp vào Định cấu hình màn hình xin phép.

    Chọn một địa chỉ email, chỉ định Tên sản phẩm rồi nhấn Lưu.

  4. Trong thẻ Credentials (Thông tin xác thực), hãy chọn danh sách thả xuống Create credential (Tạo thông tin xác thực) rồi chọn ID ứng dụng khách OAuth.

  5. Trong Loại ứng dụng, hãy chọn Ứng dụng web.

    Đăng ký các nguồn gốc mà từ đó ứng dụng của bạn được phép truy cập vào các API của Google, như thể hiện bên dưới. Nguồn gốc là sự kết hợp duy nhất giữa giao thức, tên máy chủ và cổng.

    1. Trong trường Nguồn gốc JavaScript được ủy quyền, hãy nhập nguồn gốc cho ứng dụng của bạn. Bạn có thể nhập nhiều nguồn gốc để cho phép ứng dụng chạy trên các giao thức, miền hoặc miền con khác nhau. Bạn không thể sử dụng ký tự đại diện. Trong ví dụ bên dưới, URL thứ hai có thể là URL chính thức.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. Trường URI chuyển hướng được uỷ quyền không yêu cầu giá trị. URI chuyển hướng không được sử dụng với các API JavaScript.

    3. Nhấn nút Tạo.

  6. Từ hộp thoại Ứng dụng OAuth hiện ra, hãy sao chép Mã ứng dụng. Mã ứng dụng khách cho phép ứng dụng truy cập vào các API của Google đã bật.

Bước 2: Đưa thư viện nền tảng của Google vào trang của bạn

Đưa vào các tập lệnh sau minh hoạ hàm ẩn danh để chèn tập lệnh vào DOM của trang web index.html này.

<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
  <!-- BEGIN Pre-requisites -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
  </script>
  <!-- END Pre-requisites -->

Bước 3: Khởi chạy đối tượng GoogleAuth

Tải thư viện auth2 và gọi gapi.auth2.init() để khởi tạo đối tượng GoogleAuth. Hãy chỉ định mã ứng dụng của bạn và các phạm vi mà bạn muốn yêu cầu khi gọi init().

<!-- Continuing the <head> section -->
  <script>
    function start() {
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
          // Scopes to request in addition to 'profile' and 'email'
          //scope: 'additional_scope'
        });
      });
    }
  </script>
</head>
<body>
  <!-- ... -->
</body>
</html>

Bước 4: Thêm nút đăng nhập vào trang của bạn

Thêm nút đăng nhập vào trang web của bạn và đính kèm trình xử lý lượt nhấp để gọi grantOfflineAccess() nhằm bắt đầu quy trình tạo mã một lần.

<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
  $('#signinButton').click(function() {
    // signInCallback defined in step 6.
    auth2.grantOfflineAccess().then(signInCallback);
  });
</script>

Bước 5: Đăng nhập người dùng

Người dùng nhấp vào nút đăng nhập và cấp cho ứng dụng của bạn quyền truy cập vào các quyền mà bạn đã yêu cầu. Sau đó, hàm callback mà bạn đã chỉ định trong phương thức grantOfflineAccess().then() được chuyển một đối tượng JSON có mã uỷ quyền. Ví dụ:

{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}

Bước 6: Gửi mã uỷ quyền đến máy chủ

code là mã một lần mà máy chủ của bạn có thể trao đổi lấy mã truy cập và mã làm mới của riêng mình. Bạn chỉ có thể lấy mã thông báo làm mới sau khi người dùng đã thấy hộp thoại ủy quyền yêu cầu quyền truy cập ngoại tuyến. Nếu đã chỉ định select-account prompt trong OfflineAccessOptions ở bước 4, bạn phải lưu trữ mã làm mới mà bạn truy xuất để sử dụng sau này vì các đối tác trao đổi tiếp theo sẽ trả về null cho mã thông báo làm mới. Quy trình này giúp tăng cường bảo mật cho quy trình chuẩn OAuth 2.0 của bạn.

Mã truy cập luôn được trả về cùng với việc trao đổi mã ủy quyền hợp lệ.

Tập lệnh sau đây xác định hàm callback cho nút đăng nhập. Khi đăng nhập thành công, hàm sẽ lưu trữ mã truy cập để sử dụng phía máy khách và gửi mã một lần tới máy chủ của bạn trên cùng một miền.

<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
  if (authResult['code']) {

    // Hide the sign-in button now that the user is authorized, for example:
    $('#signinButton').attr('style', 'display: none');

    // Send the code to the server
    $.ajax({
      type: 'POST',
      url: 'http://example.com/storeauthcode',
      // Always include an `X-Requested-With` header in every AJAX request,
      // to protect against CSRF attacks.
      headers: {
        'X-Requested-With': 'XMLHttpRequest'
      },
      contentType: 'application/octet-stream; charset=utf-8',
      success: function(result) {
        // Handle or verify the server response.
      },
      processData: false,
      data: authResult['code']
    });
  } else {
    // There was an error.
  }
}
</script>

Bước 7: Trao đổi mã ủy quyền cho mã thông báo truy cập

Trên máy chủ, hãy trao đổi mã xác thực để truy cập và làm mới mã thông báo. Sử dụng mã truy cập để gọi API Google thay mặt người dùng và (không bắt buộc) lưu trữ mã làm mới để lấy mã truy cập mới khi mã truy cập hết hạn.

Nếu đã yêu cầu quyền truy cập vào hồ sơ, bạn cũng sẽ nhận được một mã thông báo mã nhận dạng chứa thông tin cơ bản về hồ sơ của người dùng.

Ví dụ:

Java
// (Receive authCode via HTTPS POST)


if (request.getHeader("X-Requested-With") == null) {
  // Without the `X-Requested-With` header, this request could be forged. Aborts.
}

// Set path to the Web application client_secret_*.json file you downloaded from the
// Google API Console: https://console.cloud.google.com/apis/credentials
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "/path/to/client_secret.json";

// Exchange auth code for access token
GoogleClientSecrets clientSecrets =
    GoogleClientSecrets.load(
        JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE));
GoogleTokenResponse tokenResponse =
          new GoogleAuthorizationCodeTokenRequest(
              new NetHttpTransport(),
              JacksonFactory.getDefaultInstance(),
              "https://oauth2.googleapis.com/token",
              clientSecrets.getDetails().getClientId(),
              clientSecrets.getDetails().getClientSecret(),
              authCode,
              REDIRECT_URI)  // Specify the same redirect URI that you use with your web
                             // app. If you don't have a web version of your app, you can
                             // specify an empty string.
              .execute();

String accessToken = tokenResponse.getAccessToken();

// Use access token to call API
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Drive drive =
    new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
        .setApplicationName("Auth Code Exchange Demo")
        .build();
File file = drive.files().get("appfolder").execute();

// Get profile info from ID token
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String userId = payload.getSubject();  // Use this value as a key to identify a user.
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
Python
from apiclient import discovery
import httplib2
from oauth2client import client

# (Receive auth_code by HTTPS POST)


# If this request does not have `X-Requested-With` header, this could be a CSRF
if not request.headers.get('X-Requested-With'):
    abort(403)

# Set path to the Web application client_secret_*.json file you downloaded from the
# Google API Console: https://console.cloud.google.com/apis/credentials
CLIENT_SECRET_FILE = '/path/to/client_secret.json'

# Exchange auth code for access token, refresh token, and ID token
credentials = client.credentials_from_clientsecrets_and_code(
    CLIENT_SECRET_FILE,
    ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
    auth_code)

# Call Google API
http_auth = credentials.authorize(httplib2.Http())
drive_service = discovery.build('drive', 'v3', http=http_auth)
appfolder = drive_service.files().get(fileId='appfolder').execute()

# Get profile info from ID token
userid = credentials.id_token['sub']
email = credentials.id_token['email']