Restringir o acesso à API com chaves da API

Pode usar chaves da API para restringir o acesso a métodos da API específicos ou a todos os métodos numa API. Esta página descreve como restringir o acesso à API aos clientes que têm uma chave da API e também mostra como criar uma chave da API.

O Extensible Service Proxy (ESP) usa a API Service Control para validar uma chave da API e a respetiva associação à API ativada de um projeto. Se definir um requisito de chave da API na sua API, os pedidos ao método, à classe ou à API protegidos são rejeitados, a menos que tenham uma chave gerada no seu projeto ou noutros projetos pertencentes a programadores aos quais concedeu acesso para ativar a sua API. O projeto no qual a chave da API foi criada não está registado e não é adicionado ao cabeçalho do pedido. No entanto, pode ver o Google Cloud projeto ao qual um cliente está associado em Endpoints > Serviço, conforme descrito em Filtre por um projeto de consumidor específico.

Para ver informações sobre em que Google Cloud projeto deve ser criada uma chave da API, consulte o artigo Partilhar APIs protegidas por chave da API.

Por predefinição, nos serviços gRPC, todos os métodos da API requerem uma chave da API para aceder aos mesmos. Pode desativar o requisito de chave da API para toda a API ou para métodos específicos. Para tal, adicione uma secção de utilização à configuração do serviço e configure regras e seletores, conforme descrito nos procedimentos seguintes.

Restringir ou conceder acesso a todos os métodos da API

Para especificar que não é necessária uma chave da API para aceder à sua API:

  1. Abra o ficheiro de configuração do serviço gRPC do seu projeto num editor de texto e procure ou adicione uma secção usage.

  2. Na secção usage, especifique uma regra allow_unregistered_calls da seguinte forma. O caráter universal "*" no selector significa que a regra se aplica a todos os métodos na API.

    usage:
      rules:
      # All methods can be called without an API Key.
      - selector: "*"
        allow_unregistered_calls: true
    

Remover a restrição da chave da API para um método

Para desativar a validação da chave da API para um método específico, mesmo quando restringiu o acesso à API para a API:

  1. Abra o ficheiro de configuração do serviço gRPC do seu projeto num editor de texto e encontre ou adicione uma secção usage:

  2. Na secção usage, especifique uma regra allow_unregistered_calls da seguinte forma. O símbolo selector significa que a regra se aplica apenas ao método especificado. Neste caso, ListShelves.

    usage:
      rules:
      # ListShelves method can be called without an API Key.
      - selector: endpoints.examples.bookstore.Bookstore.ListShelves
        allow_unregistered_calls: true
    

Chamar uma API através de uma chave da API

A chamada de uma API varia consoante a chamada seja feita a partir de um cliente gRPC ou de um cliente HTTP.

Clientes gRPC

Se um método requer uma chave API, os clientes gRPC têm de transmitir o valor da chave como x-api-key metadados com a chamada do método.

Python

def run(
    host, port, api_key, auth_token, timeout, use_tls, servername_override, ca_path

Java

private static final class Interceptor implements ClientInterceptor {
  private final String apiKey;
  private final String authToken;

  private static Logger LOGGER = Logger.getLogger("InfoLogging");

  private static Metadata.Key<String> API_KEY_HEADER =
      Metadata.Key.of("x-api-key", Metadata.ASCII_STRING_MARSHALLER);
  private static Metadata.Key<String> AUTHORIZATION_HEADER =
      Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);

  public Interceptor(String apiKey, String authToken) {
    this.apiKey = apiKey;
    this.authToken = authToken;
  }

  @Override
  public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
      MethodDescriptor<ReqT,RespT> method, CallOptions callOptions, Channel next) {
    LOGGER.info("Intercepted " + method.getFullMethodName());
    ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);

    call = new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
      @Override
      public void start(Listener<RespT> responseListener, Metadata headers) {
        if (apiKey != null && !apiKey.isEmpty()) {
          LOGGER.info("Attaching API Key: " + apiKey);
          headers.put(API_KEY_HEADER, apiKey);
        }
        if (authToken != null && !authToken.isEmpty()) {
          System.out.println("Attaching auth token");
          headers.put(AUTHORIZATION_HEADER, "Bearer " + authToken);
        }
        super.start(responseListener, headers);
      }
    };
    return call;
  }
}

Go

func main() {
	flag.Parse()

	// Set up a connection to the server.
	conn, err := grpc.Dial(*addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	if *keyfile != "" {
		log.Printf("Authenticating using Google service account key in %s", *keyfile)
		keyBytes, err := ioutil.ReadFile(*keyfile)
		if err != nil {
			log.Fatalf("Unable to read service account key file %s: %v", *keyfile, err)
		}

		tokenSource, err := google.JWTAccessTokenSourceFromJSON(keyBytes, *audience)
		if err != nil {
			log.Fatalf("Error building JWT access token source: %v", err)
		}
		jwt, err := tokenSource.Token()
		if err != nil {
			log.Fatalf("Unable to generate JWT token: %v", err)
		}
		*token = jwt.AccessToken
		// NOTE: the generated JWT token has a 1h TTL.
		// Make sure to refresh the token before it expires by calling TokenSource.Token() for each outgoing requests.
		// Calls to this particular implementation of TokenSource.Token() are cheap.
	}

	ctx := context.Background()
	if *key != "" {
		log.Printf("Using API key: %s", *key)
		ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", *key)
	}
	if *token != "" {
		log.Printf("Using authentication token: %s", *token)
		ctx = metadata.AppendToOutgoingContext(ctx, "Authorization", fmt.Sprintf("Bearer %s", *token))
	}

	// Contact the server and print out its response.
	name := defaultName
	if len(flag.Args()) > 0 {
		name = flag.Arg(0)
	}
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
}

Node.js

const makeGrpcRequest = (JWT_AUTH_TOKEN, API_KEY, HOST, GREETEE) => {
  // Uncomment these lines to set their values
  // const JWT_AUTH_TOKEN = 'YOUR_JWT_AUTH_TOKEN';
  // const API_KEY = 'YOUR_API_KEY';
  // const HOST = 'localhost:50051'; // The IP address of your endpoints host
  // const GREETEE = 'world';

  // Import required libraries
  const grpc = require('@grpc/grpc-js');
  const protoLoader = require('@grpc/proto-loader');
  const path = require('path');

  // Load protobuf spec for an example API
  const PROTO_PATH = path.join(__dirname, '/protos/helloworld.proto');

  const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
  });

  const protoObj = grpc.loadPackageDefinition(packageDefinition).helloworld;

  // Create a client for the protobuf spec
  const client = new protoObj.Greeter(HOST, grpc.credentials.createInsecure());

  // Build gRPC request
  const metadata = new grpc.Metadata();
  if (API_KEY) {
    metadata.add('x-api-key', API_KEY);
  } else if (JWT_AUTH_TOKEN) {
    metadata.add('authorization', `Bearer ${JWT_AUTH_TOKEN}`);
  }

  // Execute gRPC request
  client.sayHello({name: GREETEE}, metadata, (err, response) => {
    if (err) {
      console.error(err);
    }

    if (response) {
      console.log(response.message);
    }
  });
};

Clientes HTTP

Se estiver a usar a funcionalidade de transcodificação de HTTP do Cloud Endpoints para gRPC, os clientes HTTP podem enviar a chave como um parâmetro de consulta da mesma forma que o fazem para os serviços OpenAPI.

Partilhar APIs protegidas por chave da API

As chaves da API estão associadas ao Google Cloud projeto no qual foram criadas. Se decidiu exigir uma chave da API para a sua API, o Google Cloud projeto no qual a chave da API é criada depende das respostas às seguintes perguntas:

  • Precisa de distinguir entre os autores da chamada da sua API para poder usar funcionalidades dos Endpoints, como quotas?
  • Todos os autores de chamadas da sua API têm os seus próprios Google Cloud projetos?
  • Precisa de configurar diferentes restrições da chave da API?

Pode usar a seguinte árvore de decisão como um guia para decidir em que Google Cloud projeto criar a chave da API.

Árvore de decisões da chave da API

Conceda autorização para ativar a API

Quando precisa de distinguir entre os autores da chamada da sua API e cada autor da chamada tem o seu próprio projeto, pode conceder aos principais autorização para ativar a API no seu próprio projeto. Google Cloud Google Cloud Desta forma, os utilizadores da sua API podem criar a sua própria chave da API para utilização com a sua API.

Por exemplo, suponhamos que a sua equipa criou uma API para utilização interna por vários programas cliente na sua empresa e que cada programa cliente tem o seu próprio projeto. Google CloudPara distinguir entre os autores da chamada da sua API, a chave da API de cada autor da chamada tem de ser criada num projeto Google Cloud diferente. Pode conceder aos seus colegas autorização para ativar a API no projeto Google Cloud ao qual o programa cliente está associado.

Para permitir que os utilizadores criem a sua própria chave da API:

  1. No projeto Google Cloud no qual a sua API está configurada, conceda a cada utilizador a autorização para ativar a sua API.
  2. Contacte os utilizadores e informe-os de que podem ativar a sua API no respetivo projeto Google Cloud e criar uma chave da API.

Crie um Google Cloud projeto separado para cada pessoa que liga

Quando precisa de distinguir os autores das chamadas da sua API e nem todos os autores das chamadas têm projetos, pode criar um projeto e uma chave da API separados para cada autor da chamada. Google Cloud Google Cloud Antes de criar os projetos, pense nos nomes dos projetos para poder identificar facilmente o autor da chamada associado ao projeto.

Por exemplo, suponhamos que tem clientes externos da sua API e não tem ideia de como foram criados os programas cliente que chamam a sua API. Talvez alguns dos clientes usem Google Cloud serviços e tenham um Google Cloud projeto, e talvez alguns não. Para distinguir os autores da chamada, tem de criar um Google Cloud projeto e uma chave da API separados para cada autor da chamada.

Para criar um Google Cloud projeto e uma chave da API separados para cada autor da chamada:

  1. Crie um projeto separado para cada pessoa que liga.
  2. Em cada projeto, ative a sua API e crie uma chave da API.
  3. Dê a chave da API a cada autor da chamada.

Crie uma chave da API para cada autor da chamada

Quando não precisa de distinguir entre os autores da chamada da sua API, mas quer adicionar restrições de chaves da API, pode criar uma chave da API separada para cada autor da chamada no mesmo projeto.

Para criar uma chave da API para cada autor da chamada no mesmo projeto:

  1. No projeto no qual a sua API está configurada ou num projeto no qual a API está ativada, crie uma chave da API para cada cliente que tenha as restrições da chave da API de que precisa.
  2. Dê a chave da API a cada autor da chamada.

Crie uma chave da API para todos os autores da chamada

Quando não precisa de distinguir entre os autores da chamada da sua API e não precisa de adicionar restrições de API, mas ainda quer exigir uma chave da API (para impedir o acesso anónimo, por exemplo), pode criar uma chave da API para todos os autores da chamada usarem.

Para criar uma chave da API para todos os autores da chamada:
  1. No projeto no qual a sua API está configurada ou num projeto no qual a API está ativada, crie uma chave da API para todos os autores da chamada que tenha as restrições da chave da API de que precisa.
  2. Atribuir a mesma chave da API a todos os autores da chamada.

O que se segue?