使用客户端库时进行身份验证

本页面介绍了如何使用客户端库访问 Google API。

通过客户端库,您可以更轻松地使用支持的语言访问 Google Cloud API。您可以直接通过向服务器发出原始请求来使用 Google Cloud API,但客户端库可提供简化,从而显著减少您需要编写的代码量。这对于身份验证尤其如此,因为客户端库支持应用默认凭据 (ADC)

如果您接受来自外部来源(例如客户)的凭据配置(JSON、文件或数据流),请查看使用来自外部来源的凭据配置时应满足的安全要求

将应用默认凭据与客户端库搭配使用

如需使用应用默认凭据对应用进行身份验证,您必须先为应用运行的环境设置 ADC。使用客户端库创建客户端时,客户端库会自动检查和使用您提供给 ADC 的凭据,从而向代码使用的 API 进行身份验证。您的应用无需明确对令牌进行身份验证或管理;这些要求由身份验证库自动管理。

对于本地开发环境,您可以使用 gcloud CLI 通过用户凭据服务账号模拟来设置 ADC。对于生产环境,您可以通过关联服务账号来设置 ADC。

示例客户端创建

以下代码示例为 Cloud Storage 服务创建客户端。您的代码可能需要不同的客户端;这些示例仅用于展示如何在无需任何代码来明确进行身份验证的情况下创建客户端并使用它。

您必须先完成以下步骤,然后才能运行后续示例:

Go

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/storage"
	"google.golang.org/api/iterator"
)

// authenticateImplicitWithAdc uses Application Default Credentials
// to automatically find credentials and authenticate.
func authenticateImplicitWithAdc(w io.Writer, projectId string) error {
	// projectId := "your_project_id"

	ctx := context.Background()

	// NOTE: Replace the client created below with the client required for your application.
	// Note that the credentials are not specified when constructing the client.
	// The client library finds your credentials using ADC.
	client, err := storage.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("NewClient: %w", err)
	}
	defer client.Close()

	it := client.Buckets(ctx, projectId)
	for {
		bucketAttrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintf(w, "Bucket: %v\n", bucketAttrs.Name)
	}

	fmt.Fprintf(w, "Listed all storage buckets.\n")

	return nil
}

Java


import com.google.api.gax.paging.Page;
import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import java.io.IOException;

public class AuthenticateImplicitWithAdc {

  public static void main(String[] args) throws IOException {
    // TODO(Developer):
    //  1. Before running this sample,
    //  set up Application Default Credentials as described in
    //  https://cloud.google.com/docs/authentication/external/set-up-adc
    //  2. Replace the project variable below.
    //  3. Make sure you have the necessary permission to list storage buckets
    //  "storage.buckets.list"
    String projectId = "your-google-cloud-project-id";
    authenticateImplicitWithAdc(projectId);
  }

  // When interacting with Google Cloud Client libraries, the library can auto-detect the
  // credentials to use.
  public static void authenticateImplicitWithAdc(String project) throws IOException {

    // *NOTE*: Replace the client created below with the client required for your application.
    // Note that the credentials are not specified when constructing the client.
    // Hence, the client library will look for credentials using ADC.
    //
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    Storage storage = StorageOptions.newBuilder().setProjectId(project).build().getService();

    System.out.println("Buckets:");
    Page<Bucket> buckets = storage.list();
    for (Bucket bucket : buckets.iterateAll()) {
      System.out.println(bucket.toString());
    }
    System.out.println("Listed all storage buckets.");
  }
}

Node.js

/**
 * TODO(developer):
 *  1. Uncomment and replace these variables before running the sample.
 *  2. Set up ADC as described in https://cloud.google.com/docs/authentication/external/set-up-adc
 *  3. Make sure you have the necessary permission to list storage buckets "storage.buckets.list"
 *    (https://cloud.google.com/storage/docs/access-control/iam-permissions#bucket_permissions)
 */
// const projectId = 'YOUR_PROJECT_ID';

const {Storage} = require('@google-cloud/storage');

async function authenticateImplicitWithAdc() {
  // This snippet demonstrates how to list buckets.
  // NOTE: Replace the client created below with the client required for your application.
  // Note that the credentials are not specified when constructing the client.
  // The client library finds your credentials using ADC.
  const storage = new Storage({
    projectId,
  });
  const [buckets] = await storage.getBuckets();
  console.log('Buckets:');

  for (const bucket of buckets) {
    console.log(`- ${bucket.name}`);
  }

  console.log('Listed all storage buckets.');
}

authenticateImplicitWithAdc();

PHP

// Imports the Cloud Storage client library.
use Google\Cloud\Storage\StorageClient;

/**
 * Authenticate to a cloud client library using a service account implicitly.
 *
 * @param string $projectId The Google project ID.
 */
function auth_cloud_implicit($projectId)
{
    $config = [
        'projectId' => $projectId,
    ];

    # If you don't specify credentials when constructing the client, the
    # client library will look for credentials in the environment.
    $storage = new StorageClient($config);

    # Make an authenticated API request (listing storage buckets)
    foreach ($storage->buckets() as $bucket) {
        printf('Bucket: %s' . PHP_EOL, $bucket->name());
    }
}

Python


from google.cloud import storage


def authenticate_implicit_with_adc(project_id="your-google-cloud-project-id"):
    """
    When interacting with Google Cloud Client libraries, the library can auto-detect the
    credentials to use.

    // TODO(Developer):
    //  1. Before running this sample,
    //  set up ADC as described in https://cloud.google.com/docs/authentication/external/set-up-adc
    //  2. Replace the project variable.
    //  3. Make sure that the user account or service account that you are using
    //  has the required permissions. For this sample, you must have "storage.buckets.list".
    Args:
        project_id: The project id of your Google Cloud project.
    """

    # This snippet demonstrates how to list buckets.
    # *NOTE*: Replace the client created below with the client required for your application.
    # Note that the credentials are not specified when constructing the client.
    # Hence, the client library will look for credentials using ADC.
    storage_client = storage.Client(project=project_id)
    buckets = storage_client.list_buckets()
    print("Buckets:")
    for bucket in buckets:
        print(bucket.name)
    print("Listed all storage buckets.")

Ruby

def authenticate_implicit_with_adc project_id:
  # The ID of your Google Cloud project
  # project_id = "your-google-cloud-project-id"

  ###
  # When interacting with Google Cloud Client libraries, the library can auto-detect the
  # credentials to use.
  # TODO(Developer):
  #   1. Before running this sample,
  #      set up ADC as described in https://cloud.google.com/docs/authentication/external/set-up-adc
  #   2. Replace the project variable.
  #   3. Make sure that the user account or service account that you are using
  #      has the required permissions. For this sample, you must have "storage.buckets.list".
  ###

  require "google/cloud/storage"

  # This sample demonstrates how to list buckets.
  # *NOTE*: Replace the client created below with the client required for your application.
  # Note that the credentials are not specified when constructing the client.
  # Hence, the client library will look for credentials using ADC.
  storage = Google::Cloud::Storage.new project_id: project_id
  buckets = storage.buckets
  puts "Buckets: "
  buckets.each do |bucket|
    puts bucket.name
  end
  puts "Plaintext: Listed all storage buckets."
end

将 API 密钥与客户端库搭配使用

您只能将 API 密钥与接受 API 密钥的 API 的客户端库搭配使用。此外,API 密钥不得设置任何会阻止其用于该 API 的 API 限制。

如需详细了解在快速模式下创建的 API 密钥,请参阅 Google Cloud 快速模式常见问题解答

此示例使用接受 API 密钥的 Cloud Natural Language API 来演示如何向库提供 API 密钥。

C#

如需运行此示例,您必须安装 Natural Language 客户端库


using Google.Cloud.Language.V1;
using System;

public class UseApiKeySample
{
    public void AnalyzeSentiment(string apiKey)
    {
        LanguageServiceClient client = new LanguageServiceClientBuilder
        {
            ApiKey = apiKey
        }.Build();

        string text = "Hello, world!";

        AnalyzeSentimentResponse response = client.AnalyzeSentiment(Document.FromPlainText(text));
        Console.WriteLine($"Text: {text}");
        Sentiment sentiment = response.DocumentSentiment;
        Console.WriteLine($"Sentiment: {sentiment.Score}, {sentiment.Magnitude}");
        Console.WriteLine("Successfully authenticated using the API key");
    }
}

C++

如需运行此示例,您必须安装 Natural Language 客户端库

#include "google/cloud/language/v1/language_client.h"
#include "google/cloud/credentials.h"
#include "google/cloud/options.h"

void AuthenticateWithApiKey(std::vector<std::string> const& argv) {
  if (argv.size() != 2) {
    throw google::cloud::testing_util::Usage{
        "authenticate-with-api-key <project-id> <api-key>"};
  }
  namespace gc = ::google::cloud;
  auto options = gc::Options{}.set<gc::UnifiedCredentialsOption>(
      gc::MakeApiKeyCredentials(argv[1]));
  auto client = gc::language_v1::LanguageServiceClient(
      gc::language_v1::MakeLanguageServiceConnection(options));

  auto constexpr kText = "Hello, world!";

  google::cloud::language::v1::Document d;
  d.set_content(kText);
  d.set_type(google::cloud::language::v1::Document::PLAIN_TEXT);

  auto response = client.AnalyzeSentiment(d, {});
  if (!response) throw std::move(response.status());
  auto const& sentiment = response->document_sentiment();
  std::cout << "Text: " << kText << "\n";
  std::cout << "Sentiment: " << sentiment.score() << ", "
            << sentiment.magnitude() << "\n";
  std::cout << "Successfully authenticated using the API key\n";
}

Go

如需运行此示例,您必须安装 Natural Language 客户端库

import (
	"context"
	"fmt"
	"io"

	language "cloud.google.com/go/language/apiv1"
	"cloud.google.com/go/language/apiv1/languagepb"
	"google.golang.org/api/option"
)

// authenticateWithAPIKey authenticates with an API key for Google Language
// service.
func authenticateWithAPIKey(w io.Writer, apiKey string) error {
	// apiKey := "api-key-string"

	ctx := context.Background()

	// Initialize the Language Service client and set the API key.
	client, err := language.NewClient(ctx, option.WithAPIKey(apiKey))
	if err != nil {
		return fmt.Errorf("NewClient: %w", err)
	}
	defer client.Close()

	text := "Hello, world!"
	// Make a request to analyze the sentiment of the text.
	res, err := client.AnalyzeSentiment(ctx, &languagepb.AnalyzeSentimentRequest{
		Document: &languagepb.Document{
			Source: &languagepb.Document_Content{
				Content: text,
			},
			Type: languagepb.Document_PLAIN_TEXT,
		},
	})
	if err != nil {
		return fmt.Errorf("AnalyzeSentiment: %w", err)
	}

	fmt.Fprintf(w, "Text: %s\n", text)
	fmt.Fprintf(w, "Sentiment score: %v\n", res.DocumentSentiment.Score)
	fmt.Fprintln(w, "Successfully authenticated using the API key.")

	return nil
}

Node.js

如需运行此示例,您必须安装 Natural Language 客户端库


const {
  v1: {LanguageServiceClient},
} = require('@google-cloud/language');

/**
 * Authenticates with an API key for Google Language service.
 *
 * @param {string} apiKey An API Key to use
 */
async function authenticateWithAPIKey(apiKey) {
  const language = new LanguageServiceClient({apiKey});

  // Alternatively:
  // const {GoogleAuth} = require('google-auth-library');
  // const auth = new GoogleAuth({apiKey});
  // const language = new LanguageServiceClient({auth});

  const text = 'Hello, world!';

  const [response] = await language.analyzeSentiment({
    document: {
      content: text,
      type: 'PLAIN_TEXT',
    },
  });

  console.log(`Text: ${text}`);
  console.log(
    `Sentiment: ${response.documentSentiment.score}, ${response.documentSentiment.magnitude}`
  );
  console.log('Successfully authenticated using the API key');
}

authenticateWithAPIKey();

Python

如需运行此示例,您必须安装 Natural Language 客户端库


from google.cloud import language_v1


def authenticate_with_api_key(api_key_string: str) -> None:
    """
    Authenticates with an API key for Google Language service.

    TODO(Developer): Replace this variable before running the sample.

    Args:
        api_key_string: The API key to authenticate to the service.
    """

    # Initialize the Language Service client and set the API key
    client = language_v1.LanguageServiceClient(
        client_options={"api_key": api_key_string}
    )

    text = "Hello, world!"
    document = language_v1.Document(
        content=text, type_=language_v1.Document.Type.PLAIN_TEXT
    )

    # Make a request to analyze the sentiment of the text.
    sentiment = client.analyze_sentiment(
        request={"document": document}
    ).document_sentiment

    print(f"Text: {text}")
    print(f"Sentiment: {sentiment.score}, {sentiment.magnitude}")
    print("Successfully authenticated using the API key")

当您在应用中使用 API 密钥时,请确保其在存储和传输期间均安全无虞。公开泄露 API 密钥可能会导致您的账号产生意外费用。如需了解详情,请参阅管理 API 密钥的最佳实践

使用外部来源的凭据配置时的安全要求

通常,您可以使用 gcloud CLI 命令或 Google Cloud 控制台生成凭据配置。例如,您可以使用 gcloud CLI 生成本地 ADC 文件或登录配置文件。同样,您可以使用 Google Cloud 控制台来创建和下载服务账号密钥。

不过,对于某些用例,凭据配置是由外部实体提供的;这些凭据配置旨在用于向 Google API 进行身份验证。

某些类型的凭据配置包含端点和文件路径,身份验证库会使用这些端点和文件路径来获取令牌。如果您接受来自外部来源的凭据配置,则必须先验证配置,然后才能使用该配置。如果您不验证配置,恶意行为者可能会使用凭据来危害您的系统和数据。

验证来自外部来源的凭据配置

您需要如何验证外部凭据取决于您的应用接受的凭据类型。

验证服务账号密钥

如果您的应用接受服务账号密钥,请使用特定于服务账号密钥的凭据加载器,如以下示例所示。类型专用凭据加载器仅解析服务账号密钥中存在的字段,而不会泄露任何漏洞。

C#

var saCredential = ServiceAccountCredential.FromServiceAccountData(stream);

C++

auto cred = google::cloud::MakeServiceAccountCredentials(json)

Java

ServiceAccountCredentials credentials =
      ServiceAccountCredentials.fromJson(json, new HttpTransportFactory());

Node.js

const keys = JSON.parse(json_input)
const authClient = JWT.fromJSON(keys);

PHP

cred = new Google\Auth\Credentials\ServiceAccountCredentials($scope, $jsonKey);

Python

cred = service_account.Credentials.from_service_account_info(json_data)

Ruby

creds = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: json_stream)

如果您无法使用特定于类型的凭据加载器,请通过确认 type 字段的值为 service_account 来验证凭据。如果 type 字段的值是任何其他值,请勿使用服务账号密钥。

验证其他凭据配置

如果您的应用接受服务账号密钥以外的任何类型的凭据,则必须执行额外的验证。其他类型的凭据配置示例包括 ADC 凭据文件工作负载身份联合凭据文件员工身份联合登录配置文件

下表列出了您需要验证的字段(如果您的凭据中包含这些字段)。并非所有凭据配置都包含所有这些字段。

字段 用途 预期值
service_account_impersonation_url 身份验证库使用此字段访问端点,以便为被模拟的服务账号生成访问令牌。 https://iamcredentials.googleapis.com.com/v1/projects/-/serviceAccounts/service account email:generateAccessToken
token_url 身份验证库会将外部令牌发送到此端点,以将其换成联合访问令牌 https://sts.googleapis.com.com/v1/token
credential_source.file 身份验证库会从此字段指定的位置读取文件中的外部令牌,并将其发送到 token_url 端点。 包含外部令牌的文件的路径。您应该会认出此路径。
credential_source.url 返回外部令牌的端点。身份验证库会向此网址发送请求,并将响应发送到 token_url 端点。

以下任一项:

  • 您的云服务提供商提供的众所周知的端点。
  • 您已明确设置为提供令牌的端点。
credential_source.executable.command 如果 GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES 环境变量设置为 1,身份验证库会运行此命令或可执行文件。 返回外部令牌的可执行文件或命令。 您应该识别此命令并验证其安全性。
credential_source.aws.url 身份验证库会向此网址发出请求,以检索 AWS 安全令牌。

以下任一确切值:

  • http://169.254.169.254/latest/meta-data/iam/security-credentials
  • http://[fd00:ec2::254]/latest/meta-data/iam/security-credentials
credential_source.aws.region_url 身份验证库会向此网址发出请求,以检索有效的 AWS 区域。

以下任一确切值:

  • http://169.254.169.254/latest/meta-data/placement/availability-zone
  • http://[fd00:ec2::254]/latest/meta-data/placement/availability-zone
credential_source.aws.imdsv2_session_token_url 身份验证库会向此网址发出请求以检索 AWS 会话令牌。

以下任一确切值:

  • http://169.254.169.254/latest/api/token
  • http://[fd00:ec2::254]/latest/api/token

后续步骤