Limitazione dell'accesso alle API con le chiavi API

Puoi utilizzare le chiavi API per limitare l'accesso a metodi API specifici o a tutti i metodi di un'API. Questa pagina descrive come limitare l'accesso alle API ai client che hanno una chiave API e mostra anche come creare una chiave API.

The Extensible Service Proxy (ESP) utilizza Service ControlAPI per convalidare una chiave API e la sua associazione all' API abilitata di un progetto. Se imposti un requisito della chiave API nella tua API, le richieste al metodo, alla classe o all'API protetti vengono rifiutate a meno che non abbiano una chiave generata nel tuo progetto o in altri progetti appartenenti a sviluppatori a cui hai concesso l'accesso per abilitare la tua API. Il progetto in cui è stata creata la chiave API non viene registrato e non viene aggiunto all'intestazione della richiesta. Tuttavia, puoi visualizzare il Google Cloud progetto a cui è associato un client in Endpoints > Servizio, come descritto in Filtrare per un progetto consumer specifico.

Per informazioni sul Google Cloud progetto in cui deve essere creata una chiave API, consulta Condividere le API protette dalla chiave API.

Per impostazione predefinita, nei servizi gRPC, tutti i metodi API richiedono una chiave API per accedervi. Puoi disattivare il requisito della chiave API per l'intera API o per metodi specifici. Per farlo, aggiungi una sezione di utilizzo alla configurazione del servizio e configura regole e selettori, come descritto nelle procedure seguenti.

Limitare o concedere l'accesso a tutti i metodi API

Per specificare che non è necessaria una chiave API per accedere alla tua API:

  1. Apri il file di configurazione del servizio gRPC del tuo progetto in un editor di testo e trova o aggiungi una sezione usage.

  2. Nella sezione usage, specifica una regola allow_unregistered_calls come segue. Il carattere jolly "*" nel selector indica che la regola si applica a tutti i metodi dell'API.

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

Rimuovere la limitazione della chiave API per un metodo

Per disattivare la convalida della chiave API per un metodo specifico anche quando hai limitato l'accesso API per l'API:

  1. Apri il file di configurazione del servizio gRPC del tuo progetto in un editor di testo e trova o aggiungi una sezione usage:

  2. Nella sezione usage, specifica una regola allow_unregistered_calls come segue. Il selector indica che la regola si applica solo al metodo specificato, in questo caso ListShelves.

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

Chiamare un'API utilizzando una chiave API

La chiamata a un'API varia a seconda che tu chiami da un client gRPC o da un client HTTP.

Client gRPC

Se un metodo richiede una chiave API, i client gRPC devono passare il valore della chiave come x-api-key metadati con la chiamata al metodo.

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);
    }
  });
};

Client HTTP

Se utilizzi la funzionalità di transcodifica HTTP di Cloud Endpoints per gRPC, i client HTTP possono inviare la chiave come parametro di query nello stesso modo in cui lo fanno per i servizi OpenAPI.

Condividere le API protette dalla chiave API

Le chiavi API sono associate al Google Cloud progetto in cui sono state create. Se hai deciso di richiedere una chiave API per la tua API, il Google Cloud progetto in cui viene creata la chiave API dipende da le risposte alle seguenti domande:

  • Devi distinguere tra gli utenti che chiamano la tua API in modo da poter utilizzare le funzionalità di Endpoints come quote?
  • Tutti gli utenti che chiamano la tua API hanno i propri Google Cloud progetti?
  • Devi configurare limitazioni diverse per le chiavi API restrictions?

Puoi utilizzare la seguente struttura decisionale come guida per decidere in quale Google Cloud progetto creare la chiave API.

Albero decisionale della chiave API

Concedere l'autorizzazione per abilitare l'API

Quando devi distinguere tra gli utenti che chiamano la tua API e ogni utente ha il proprio Google Cloud progetto, puoi concedere ai principali l'autorizzazione per abilitare l'API nel proprio Google Cloud progetto. In questo modo, gli utenti della tua API possono creare la propria chiave API da utilizzare con la tua API.

Supponiamo, ad esempio, che il tuo team abbia creato un'API per l'uso interno da parte di vari programmi client della tua azienda e che ogni programma client abbia il proprio Google Cloud progetto. Per distinguere tra gli utenti che chiamano la tua API, la chiave API per ogni utente deve essere creata in un Google Cloud progetto diverso. Puoi concedere ai tuoi colleghi l'autorizzazione per abilitare l'API nel Google Cloud progetto a cui è associato il programma client.

Per consentire agli utenti di creare la propria chiave API:

  1. Nel Google Cloud progetto in cui è configurata la tua API, concedi a ogni utente l' autorizzazione per abilitare la tua API.
  2. Contatta gli utenti e informa che possono abilitare la tua API nel proprio Google Cloud progetto e creare una chiave API.

Creare unprogetto separato Google Cloud per ogni utente che chiama

Quando devi distinguere tra gli utenti che chiamano la tua API e non tutti gli utenti che chiamano hanno Google Cloud progetti, puoi creare un Google Cloud progetto e una chiave API separati per ogni utente che chiama. Prima di creare i progetti, valuta attentamente i nomi dei progetti in modo da poter identificare facilmente il chiamante associato al progetto.

Supponiamo, ad esempio, di avere clienti esterni della tua API e tu non abbia idea di come siano stati creati i programmi client che chiamano la tua API. Forse alcuni client utilizzano Google Cloud servizi e hanno un Google Cloud progetto, e forse alcuni non lo fanno. Per distinguere tra gli utenti che chiamano, devi creare un progetto e una chiave API separati Google Cloud per ogni utente che chiama.

Per creare unprogetto e una chiave API separati per ogni utente che chiama: Google Cloud

  1. Crea un progetto separato per ogni utente che chiama.
  2. In ogni progetto, abilita la tua API e crea una chiave API.
  3. Fornisci la chiave API a ogni utente che chiama.

Creare una chiave API per ogni utente che chiama

Quando non devi distinguere tra gli utenti che chiamano la tua API, ma vuoi aggiungere limitazioni alle chiavi API, puoi creare una chiave API separata per ogni utente che chiama nello stesso progetto.

Per creare una chiave API per ogni utente che chiama nello stesso progetto:

  1. Nel progetto in cui è configurata la tua API o in un progetto in cui la tua API è abilitata, crea una chiave API per ogni cliente che abbia le limitazioni alle chiavi API di cui hai bisogno.
  2. Fornisci la chiave API a ogni utente che chiama.

Creare una chiave API per tutti gli utenti che chiamano

Quando non devi distinguere tra gli utenti che chiamano la tua API e non devi aggiungere limitazioni alle API ma vuoi comunque richiedere una chiave API (per impedire l'accesso anonimo, ad esempio), puoi creare una chiave API da utilizzare per tutti gli utenti che chiamano.

Per creare una chiave API per tutti gli utenti che chiamano:
  1. Nel progetto in cui è configurata la tua API o in un progetto in cui è abilitata la tua API, crea una chiave API per tutti gli utenti che chiamano con le limitazioni alle chiavi API di cui hai bisogno.
  2. Fornisci la stessa chiave API a ogni utente che chiama.

Restrizioni delle applicazioni

Le limitazioni delle applicazioni specificano quali siti web, indirizzi IP o app possono utilizzare la tua chiave API. Per ulteriori informazioni, vedi Aggiungere limitazioni delle applicazioni.

Nota: se utilizzi Referrer HTTP (siti web) come limitazione delle applicazioni, devi includere uno schema (ad esempio https://) quando aggiungi la limitazione del sito web. Ad esempio, https://example.com/* è una limitazione valida, ma example.com/* non lo è.

Passaggi successivi