Limitazione dell'accesso all'API con le chiavi API

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

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

Per informazioni su quale progetto Google Cloud dovrebbe essere una chiave API create in, consulta Condivisione delle API protette dalla chiave API.

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

Limitare o concedere l'accesso a tutti i metodi dell'API

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

  1. Apri il file di configurazione del servizio gRPC del 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 "*" in 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
    

Rimozione della limitazione della chiave API per un metodo

Per disattivare la convalida della chiave API per un determinato metodo anche se hai limitato l'accesso all'API per l'API:

  1. Apri la finestra di dialogo del progetto Configurazione del servizio gRPC in un editor di testo e trova o aggiungi una sezione usage:

  2. Nella sezione usage, specifica una regola allow_unregistered_calls come segue. 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 di un'API varia a seconda che venga eseguita 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 metadata 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;
  }
}

Vai

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');
  const path = require('path');

  // Load protobuf spec for an example API
  const PROTO_PATH = path.join(__dirname, '/protos/helloworld.proto');
  const protoObj = grpc.load(PROTO_PATH).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 Cloud Endpoints per gRPC Funzionalità di transcodifica HTTP, client HTTP possono inviare la chiave come parametro di query nello stesso modo in cui Servizi OpenAPI.

Condivisione di API protette da una chiave API

Le chiavi API sono associate al progetto Google Cloud in cui per cui sono stati creati. Se decidi di richiedere una chiave API per dell'API, il progetto Google Cloud in cui viene creata la chiave API dipende le risposte alle seguenti domande:

  • Devi distinguere tra i chiamanti della tua API per poter utilizzare le funzionalità di Endpoints, come le quote?
  • Tutti gli utenti che chiamano la tua API hanno i propri progetti Google Cloud?
  • Occorre configurare diversi Chiave API limitazioni?

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

Albero decisionale per le chiavi API

Concedi l'autorizzazione per abilitare l'API

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

Ad esempio, supponiamo che il tuo team abbia creato un'API per uso interno da parte di vari programmi per i clienti della tua azienda, e ogni programma cliente ha il proprio progetto. Per distinguere tra i chiamanti dell'API, la chiave API per ogni chiamante devono essere creati in un altro progetto Google Cloud. Puoi concedere ai tuoi colleghi l'autorizzazione per abilitare l'API nel progetto Google Cloud a cui è associato il programma client associati.

Per consentire agli utenti di creare la propria chiave API:

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

Creare un progetto Google Cloud separato per ogni chiamante

Quando devi distinguere tra i chiamanti della tua API e non tutti hanno progetti Google Cloud, puoi creare un progetto Google Cloud separato Chiave API per ogni chiamante. Prima di creare i progetti, valuta attentamente i nomi in modo da poter identificare facilmente il chiamante associato al progetto.

Ad esempio, supponiamo che tu abbia clienti esterni della tua API e non hai idea di come sono stati creati i programmi client che chiamano la tua API. Forse alcuni dei clienti utilizzano i servizi Google Cloud e hanno un progetto Google Cloud, mentre altri no. Per distinguere i chiamanti, devi creare un progetto Google Cloud e una chiave API distinti per ogni chiamante.

Per creare un progetto Google Cloud e una chiave API separati per ogni chiamante:

  1. Crea un progetto separato per ogni chiamante.
  2. In ogni progetto, abilita l'API e creare una chiave API.
  3. Fornisci la chiave API a ciascun chiamante.

Crea una chiave API per ogni chiamante

Quando non devi distinguere tra i chiamanti dell'API, ma vuoi per aggiungere limitazioni delle chiavi API, puoi creare una chiave API separata per ogni chiamante all'interno dello stesso progetto.

Per creare una chiave API per ogni chiamante nello stesso progetto:

  1. Nel progetto in cui è configurata l'API o in un progetto che l'API sia abilitata in, creare una chiave API per ogni cliente che dispone Chiave API restrizioni di cui hai bisogno.
  2. Fornisci la chiave API a ciascun chiamante.

Crea un'unica chiave API per tutti i chiamanti

Quando non devi distinguere tra chiamanti della tua API e non devi aggiungere limitazioni per le API, ma vuoi comunque richiedere una chiave API (ad esempio per impedire l'accesso anonimo), puoi creare una chiave API da utilizzare per tutti i chiamanti.

Per creare un'unica chiave API per tutti i chiamanti:
  1. Nel progetto in cui è configurata l'API o in un progetto che l'API sia abilitata in, creare una chiave API per tutti i chiamanti.
  2. Assegna la stessa chiave API a tutti gli utenti che chiamano.

Passaggi successivi