Xác thực và kết nối với cơ sở dữ liệu

Yêu cầu về kết nối

Sau đây là những yêu cầu đối với ứng dụng Cloud Firestore:

  • Trình điều khiển phải kết nối ở chế độ load balanced (cân bằng tải). Điều này giúp ngăn trình điều khiển cố gắng tìm hiểu cấu trúc liên kết chính xác của máy chủ mà chúng đang kết nối.
  • Trình điều khiển phải kết nối khi bật SSL.
  • Trình điều khiển phải tắt các thao tác ghi có thể thử lại. Cloud Firestore không hỗ trợ các thao tác ghi có thể thử lại. Bạn không cần tắt các thao tác đọc có thể thử lại vì chúng được hỗ trợ.

Truy xuất chuỗi kết nối

Chuỗi kết nối cơ sở dữ liệu phụ thuộc vào UID của cơ sở dữ liệu, vị trí của cơ sở dữ liệu và cơ chế xác thực. Hướng dẫn sau đây mô tả cách tạo chuỗi kết nối.

Chuỗi kết nối chính xác phụ thuộc vào cơ chế xác thực, nhưng chuỗi kết nối cơ sở sử dụng định dạng sau:

mongodb://UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&tls=true&retryWrites=false

Bạn có thể lấy chuỗi kết nối cơ sở theo một trong những cách sau:

Bảng điều khiển Firebase
  1. Trong bảng điều khiển Firebase, hãy chuyển đến trang Cơ sở dữ liệu Firestore.

    Chuyển đến Cơ sở dữ liệu Firestore

  2. Nhấp vào cơ sở dữ liệu mà bạn muốn xác thực.
  3. Trong bảng điều khiển Trình khám phá, hãy nhấp vào biểu tượng Xem thêm.
  4. Chọn Kết nối bằng các công cụ MongoDB.
  5. Sao chép chuỗi kết nối.
gcloud

Sử dụng gcloud firestore database describe để truy xuất thông tin về UID và vị trí:

gcloud firestore databases describe \
--database=DATABASE_ID \
--format='yaml(locationId, uid)'

Thay thế DATABASE_ID bằng mã nhận dạng cơ sở dữ liệu.

Kết quả đầu ra bao gồm vị trí và UID của cơ sở dữ liệu. Sử dụng thông tin này để tạo chuỗi kết nối cơ sở.

Sử dụng chuỗi kết nối cơ sở và một trong những phương thức sau để xác thực và kết nối với cơ sở dữ liệu:

Kết nối bằng Tên người dùng và mật khẩu (SCRAM)

Hãy làm theo các bước sau để tạo thông tin xác thực người dùng cho cơ sở dữ liệu và kết nối với cơ sở dữ liệu.

Trước khi bắt đầu

Để có được các quyền cần thiết để tạo người dùng, hãy yêu cầu quản trị viên cấp cho bạn vai trò IAM userCredsAdmin (roles/datastore.userCredsAdmin) trên cơ sở dữ liệu. Để biết thêm thông tin về cách cấp vai trò, hãy xem bài viết Quản lý quyền truy cập vào dự án, thư mục và tổ chức.

Bạn cũng có thể nhận được các quyền cần thiết thông qua vai trò tuỳ chỉnh hoặc các vai trò xác định trước khác.

Tạo người dùng và kết nối với cơ sở dữ liệu

Để tạo người dùng cho cơ sở dữ liệu Cloud Firestore, hãy sử dụng một trong những phương thức sau:

Bảng điều khiển Google Cloud
  1. Trong bảng điều khiển Cloud, hãy chuyển đến trang Cơ sở dữ liệu.

    Chuyển đến Cơ sở dữ liệu

  2. Chọn một cơ sở dữ liệu trong danh sách cơ sở dữ liệu.
  3. Trong trình đơn điều hướng, hãy nhấp vào Bảo mật.
  4. Nhấp vào Thêm người dùng.
  5. Nhập Tên người dùng.
  6. Chọn một vai trò cho người dùng mới.
  7. Nhấp vào Thêm.

    Mật khẩu của người dùng mới sẽ xuất hiện trong hộp thoại xác nhận.

gcloud CLI
  1. Để xác thực bằng SCRAM, trước tiên, bạn phải tạo thông tin xác thực người dùng. Sử dụng lệnh gcloud firestore user-creds:
    gcloud firestore user-creds create USERNAME --database=DATABASE_ID
    Thay thế những nội dung sau:
    • USERNAME: tên người dùng cần tạo.
    • DATABASE_ID: mã nhận dạng cơ sở dữ liệu.

    Kết quả của lệnh này bao gồm mật khẩu của người dùng.

    Kết quả đầu ra sẽ tương tự như sau:

    name: projects/PROJECT_NAME/databases/DATABASE_ID/userCreds/USERNAME
    resourceIdentity:
      principal: principal://firestore.googleapis.com/projects/PROJECT_NUMBER/name/databases/DATABASE_ID/userCreds/USERNAME
    securePassword: PASSWORD
  2. Theo mặc định, thông tin xác thực người dùng mới này không có quyền nào. Để có quyền truy cập đọc và ghi vào cơ sở dữ liệu, hãy thêm vai trò roles/datastore.user cho cơ sở dữ liệu cụ thể này:

    gcloud projects add-iam-policy-binding PROJECT_NAME \
    --member='principal://firestore.googleapis.com/projects/PROJECT_NUMBER/name/databases/DATABASE_ID/userCreds/USERNAME' \
    --role=roles/datastore.user \
    --condition='expression=resource.name == "projects/PROJECT_NAME/databases/DATABASE_ID",title="CONDITION_TITLE"'
    Thay thế những nội dung sau:
Java

Phần này cung cấp một ví dụ về mã để tạo thông tin xác thực người dùng và định cấu hình chính sách IAM bằng thư viện ứng dụng quản trị Java. Mẫu này sử dụng thư viện Ứng dụng quản trị Firestore để tạo tên người dùng và mật khẩu, đồng thời sử dụng thư viện Google Cloud Resource Manager để định cấu hình IAM.

Đối với bản dựng Maven, bạn có thể sử dụng các toạ độ sau:

com.google.cloud:google-cloud-firestore-admin:3.33.1
com.google.cloud:google-cloud-resourcemanager:1.76.0

Cung cấp thông tin xác thực người dùng và chính sách IAM:

import com.google.cloud.firestore.v1.FirestoreAdminClient;
import com.google.cloud.resourcemanager.v3.ProjectName;
import com.google.cloud.resourcemanager.v3.ProjectsClient;
import com.google.firestore.admin.v1.CreateUserCredsRequest;
import com.google.firestore.admin.v1.GetUserCredsRequest;
import com.google.firestore.admin.v1.UserCreds;
import com.google.iam.v1.Binding;
import com.google.iam.v1.GetIamPolicyRequest;
import com.google.iam.v1.GetPolicyOptions;
import com.google.iam.v1.Policy;
import com.google.iam.v1.SetIamPolicyRequest;
import com.google.protobuf.FieldMask;
import com.google.type.Expr;

public class FirestoreUserCredsExample {
  /**
   * Provision user credentials and configure an IAM policy to allow SCRAM authentication into the
   * specified Firestore with Mongo Compatibility database.
   */
  private static void provisionFirestoreUserCredsAndIAM(
      String projectId, String databaseId, String userName) throws Exception {
    UserCreds userCreds = createUserCreds(projectId, databaseId, userName);

    // Note the password returned in the UserCreds proto - it cannot be retrieved again
    // after the initial call to the createUserCreds API.
    System.out.printf(
        "Created credentials for username: %s:\nIAM principal: %s\nPassword: [%s]\n",
        userName, userCreds.getResourceIdentity().getPrincipal(), userCreds.getSecurePassword());

    // Provision an IAM binding for the principal associated with these user credentials.
    updateIamPolicyForUserCreds(projectId, databaseId, userName, userCreds);

    // Emit the password again.
    System.out.printf(
        "Successfully configured IAM policy for database: %s, username: %s\n",
        databaseId, userName);
    System.out.printf("Please make a note of the password: [%s]\n", userCreds.getSecurePassword());
  }

  /** Provision new user credentials using the FirestoreAdminClient. */
  private static UserCreds createUserCreds(String projectId, String databaseId, String userName)
      throws Exception {
    FirestoreAdminClient firestoreAdminClient = FirestoreAdminClient.create();
    return firestoreAdminClient.createUserCreds(
        CreateUserCredsRequest.newBuilder()
            .setParent(String.format("projects/%s/databases/%s", projectId, databaseId))
            .setUserCredsId(userName)
            .build());
  }

  /** Update the IAM policy using the Resource Manager ProjectsClient. */
  private static void updateIamPolicyForUserCreds(
      String projectId, String databaseId, String userName, UserCreds userCreds) throws Exception {
    try (ProjectsClient projectsClient = ProjectsClient.create()) {
      ProjectName projectName = ProjectName.of(projectId);

      // Get the current IAM policy.
      Policy currentPolicy =
          projectsClient.getIamPolicy(
              GetIamPolicyRequest.newBuilder()
                  .setResource(projectName.toString())
                  .setOptions(GetPolicyOptions.newBuilder().setRequestedPolicyVersion(3).build())
                  .build());

      String role = "roles/datastore.user";
      String title = String.format("Conditional IAM binding for %s", userName);
      String expression =
          String.format("resource.name == \"projects/%s/databases/%s\"", projectId, databaseId);

      // Construct an updated IAM policy with an additional binding for the user credentials.
      Policy.Builder policyBuilder = currentPolicy.toBuilder();
      Binding newBinding =
          Binding.newBuilder()
              .setRole(role)
              .setCondition(Expr.newBuilder().setTitle(title).setExpression(expression).build())
              .addMembers(userCreds.getResourceIdentity().getPrincipal())
              .build();
      policyBuilder.addBindings(newBinding);

      // Update the policy
      SetIamPolicyRequest request =
          SetIamPolicyRequest.newBuilder()
              .setResource(projectName.toString())
              .setPolicy(policyBuilder.build())
              .setUpdateMask(FieldMask.newBuilder().addPaths("bindings").addPaths("etag").build())
              .build();
      System.out.println(request);

      Policy updatedPolicy = projectsClient.setIamPolicy(request);
      System.out.println("Policy updated successfully: " + updatedPolicy);
    }
  }
}
Python

Phần này cung cấp một ví dụ về mã để tạo thông tin xác thực người dùng và định cấu hình chính sách IAM bằng thư viện ứng dụng quản trị Python. Mẫu này sử dụng thư viện ứng dụng Google Cloud API Firestore để tạo tên người dùng và mật khẩu, đồng thời sử dụng thư viện ứng dụng Google Cloud Iam APIthư viện ứng dụng Google Cloud Resource Manager API để định cấu hình IAM.

Bạn có thể cài đặt các thư viện Python cần thiết bằng công cụ pip:

pip install google-cloud-iam
pip install google-cloud-firestore
pip install google-cloud-resource-manager

Cung cấp thông tin xác thực người dùng và chính sách IAM:

from google.cloud import resourcemanager_v3
from google.cloud.firestore_admin_v1 import FirestoreAdminClient
from google.cloud.firestore_admin_v1 import types
from google.iam.v1 import iam_policy_pb2
from google.iam.v1 import policy_pb2
from google.type import expr_pb2


def create_user_creds(project_id: str, database_id: str, user_name: str):
  """Provision new user credentials using the FirestoreAdminClient."""
  client = FirestoreAdminClient()
  request = types.CreateUserCredsRequest(
      parent=f'projects/{project_id}/databases/{database_id}',
      user_creds_id=user_name,
  )
  response = client.create_user_creds(request)
  return response


def update_iam_policy_for_user_creds(
    project_id: str, database_id: str, user_name: str, user_creds
):
  """Update the IAM policy using the Resource Manager ProjectsClient."""
  client = resourcemanager_v3.ProjectsClient()
  request = iam_policy_pb2.GetIamPolicyRequest()
  request.resource = f'projects/{project_id}'
  request.options.requested_policy_version = 3

  # Get the current IAM policy
  current_policy = client.get_iam_policy(request)

  # Construct an updated IAM policy with an additional binding
  # for the user credentials.
  updated_policy = policy_pb2.Policy()
  binding = policy_pb2.Binding()
  iam_condition = expr_pb2.Expr()

  iam_condition.title = f'Conditional IAM binding for {user_name}'
  iam_condition.expression = (
      f'resource.name == "projects/{project_id}/databases/{database_id}"'
  )

  binding.role = 'roles/datastore.user'
  binding.condition.CopyFrom(iam_condition)
  binding.members.append(user_creds.resource_identity.principal)
  updated_policy.bindings.append(binding)

  # Update the policy
  updated_policy.MergeFrom(current_policy)
  set_policy_request = iam_policy_pb2.SetIamPolicyRequest()
  set_policy_request.resource = f'projects/{project_id}'
  set_policy_request.policy.CopyFrom(updated_policy)

  final_policy = client.set_iam_policy(set_policy_request)
  print(f'Policy updated successfully {final_policy}')


def provision_firestore_user_creds_and_iam(
    project_id: str, database_id: str, user_name: str
):
  """Provision user credentials and configure an IAM policy."""
  user_creds = create_user_creds(project_id, database_id, user_name)

  # Note the password returned in the UserCreds proto - it cannot be
  # retrieved again after the initial call to the create_user_creds API.
  print(f'Created credentials for username: {user_name}')
  print(f'IAM principal: {user_creds.resource_identity.principal}')
  print(f'Password: [{user_creds.secure_password}]')

  # Provision an IAM binding for the principal associated with
  # these user credentials.
  update_iam_policy_for_user_creds(
      project_id, database_id, user_name, user_creds
  )

  # Emit the password again
  print(
      f'Successfully configured IAM policy for database: {database_id},'
      f' username: {user_name}'
  )
  print(f'Please make a note of the password: [{user_creds.secure_password}]')

Sử dụng chuỗi kết nối sau để kết nối với cơ sở dữ liệu bằng SCRAM:

mongodb://USERNAME:PASSWORD@UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&authMechanism=SCRAM-SHA-256&tls=true&retryWrites=false

Thay thế những nội dung sau:

  • USERNAME: tên người dùng.
  • PASSWORD: mật khẩu mà bạn đã tạo cho người dùng này.
  • UID: UID của cơ sở dữ liệu. Ví dụ: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • LOCATION: vị trí của cơ sở dữ liệu.
  • DATABASE_ID: mã nhận dạng cơ sở dữ liệu.

Kết nối bằng Thư viện Uỷ quyền của Google

Mẫu mã sau đây đăng ký trình xử lý gọi lại OIDC sử dụng Google Cloud thư viện OAuth tiêu chuẩn.

Thư viện này cho phép bạn sử dụng một số loại xác thực (Thông tin xác thực mặc định của ứng dụng, Liên kết danh tính Workload Identity).

Điều này yêu cầu bạn phải thêm thư viện uỷ quyền làm phần phụ thuộc:

// Maven
<dependency>
  <groupId>com.google.auth</groupId>
  <artifactId>google-auth-library-oauth2-http</artifactId>
  <version>1.19.0</version>
</dependency>

// Gradle
implementation 'com.google.auth:google-auth-library-oauth2-http:1.19.0'

Mã mẫu sau đây minh hoạ cách kết nối:

val db = MongoClients.create(
    clientSettings(
      "DATABASE_UID",
      "LOCATION"
    ).build()
  ).getDatabase("DATABASE_ID")


/**
 * Creates a connection to a Firestore with MongoDB Compatibility database.
 * @param databaseUid The uid of the database to connect to as a string. For example: f116f93a-519c-208a-9a72-3ef6c9a1f081
 * @param locationId The location of the database to connect to, for example: nam5, us-central1, us-east4 etc...
 * @param environment Determines whether to try and fetch an authentication credential from the
 * Compute Engine VM metadata service or whether to call gcloud.
 */
private static MongoClientSettings.Builder clientSettings(
  String databaseUid: String
  String locationId:String
): MongoClientSettings.Builder {
  MongoCredential credential =
    MongoCredential.createOidcCredential(null)
      .withMechanismProperty(
        MongoCredential.OIDC_CALLBACK_KEY,
        new MongoCredential.OidcCallback() {
          @Override
          MongoCredential.OidcCallbackResult onRequest(
MongoCredential.OidcCallbackContext context) {
     // Customize this credential builder for additional credential types.
     GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
            return new MongoCredential.OidcCallbackResult(
         credentials.getAccessToken().getTokenValue(),
         Duration.between(Instant.now(),
credentials.getAccessToken().getExpirationTime().toInstant()));
          }
        },
      );
  return MongoClientSettings.builder()
    .hosts(listOf(ServerAddress(
        "$databaseUid.$locationId.firestore.goog", 443)))
    .credential(credential)
    .applyToClusterSettings(builder ->
         builder.mode(ClusterConnectionMode.LOAD_BALANCED))
    ).applyToSslSettings(ssl -> ssl.enabled(true)).retryWrites(false);
}

Thay thế những nội dung sau:

  • DATABASE_UID: UID của cơ sở dữ liệu. Ví dụ: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • LOCATION: vị trí của cơ sở dữ liệu.
  • DATABASE_ID mã nhận dạng cơ sở dữ liệu.

Kết nối từ môi trường tính toán Google Cloud

Phần này mô tả cách kết nối với Cloud Firestore từ môi trường tính toán Google Cloud, chẳng hạn như Compute Engine hoặc dịch vụ Cloud Run hoặc công việc.

Kết nối từ VM Compute Engine

Bạn có thể xác thực và kết nối với cơ sở dữ liệu bằng tài khoản dịch vụ Compute Engine. Để thực hiện việc này, hãy tạo chính sách IAM cho dự án Google Cloud chứa cơ sở dữ liệu của bạn.

Trước khi bắt đầu

Định cấu hình tài khoản dịch vụ do người dùng quản lý cho VM:

Xem hướng dẫn trong phần Định cấu hình thông tin xác thực để hoàn tất việc định cấu hình chính sách IAM cho tài khoản dịch vụ Compute Engine.

Kết nối từ Cloud Run

Bạn có thể xác thực và kết nối với cơ sở dữ liệu bằng tài khoản dịch vụ Cloud Run. Để thực hiện việc này, hãy tạo chính sách IAM cho dự án Google Cloud chứa cơ sở dữ liệu của bạn.

Trước khi bắt đầu

Xem hướng dẫn trong phần Định cấu hình thông tin xác thực để hoàn tất việc định cấu hình chính sách IAM cho tài khoản dịch vụ Cloud Run.

Định cấu hình thông tin xác thực

Để cấp cho tài khoản dịch vụ vai trò roles/datastore.user để đọc và ghi vào Cloud Firestore, hãy chạy lệnh sau:

gcloud projects add-iam-policy-binding PROJECT_NAME --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" --role=roles/datastore.user

Thay thế những nội dung sau:

  • PROJECT_NAME: tên dự án của bạn.
  • SERVICE_ACCOUNT_EMAIL: địa chỉ email cho tài khoản dịch vụ mà bạn đã tạo.

Tạo chuỗi kết nối

Sử dụng định dạng sau để tạo chuỗi kết nối:

mongodb://DATABASE_UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&tls=true&retryWrites=false&authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:FIRESTORE

Thay thế những nội dung sau:

  • DATABASE_UID: UID của cơ sở dữ liệu. Ví dụ: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • LOCATION: vị trí của cơ sở dữ liệu.
  • DATABASE_ID mã nhận dạng cơ sở dữ liệu.

Để biết thêm thông tin về cách truy xuất UID và vị trí, hãy xem bài viết Truy xuất chuỗi kết nối.

Kết nối bằng mã truy cập tạm thời

Bạn có thể sử dụng mã truy cập tạm thời Google Cloud để chạy các công cụ chẩn đoán như mongosh. Bạn có thể sử dụng gcloud auth print-access-token để xác thực bằng mã truy cập ngắn hạn. Mã thông báo này có hiệu lực trong một giờ.

Ví dụ: sử dụng lệnh sau để kết nối với cơ sở dữ liệu bằng mongosh:

mongosh --tls \
      --username access_token --password $(gcloud auth print-access-token) \
      'mongodb://UID.LOCATION.firestore.goog:443/DATABASE_ID?loadBalanced=true&authMechanism=PLAIN&authSource=$external&retryWrites=false'

Thay thế những nội dung sau:

  • DATABASE_UID: UID của cơ sở dữ liệu. Ví dụ: f116f93a-519c-208a-9a72-3ef6c9a1f081
  • LOCATION: vị trí cơ sở dữ liệu
  • DATABASE_ID: mã nhận dạng cơ sở dữ liệu