Autenticazione degli utenti con PHP

Le app in esecuzione su piattaforme gestite Google Cloud come App Engine possono evitare di gestire l'autenticazione utente e la gestione delle sessioni utilizzando Identity-Aware Proxy (IAP) per controllare l'accesso. IAP non solo può controllare l'accesso all'app, ma fornisce anche informazioni sugli utenti autenticati, tra cui l'indirizzo email e un identificatore persistente per l'app sotto forma di nuove intestazioni HTTP.

Obiettivi

  • Richiedi agli utenti della tua app App Engine di autenticarsi utilizzando IAP.

  • Accedi alle identità degli utenti nell'app per visualizzare l'indirizzo email autenticato dell'utente corrente.

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il calcolatore prezzi.

I nuovi utenti di Google Cloud potrebbero avere diritto a una prova senza costi.

Al termine delle attività descritte in questo documento, puoi evitare l'addebito di ulteriori costi eliminando le risorse che hai creato. Per saperne di più, consulta Esegui la pulizia.

Prima di iniziare

  1. Accedi al tuo account Google Cloud . Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti senza costi per l'esecuzione, il test e il deployment dei workload.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Installa Google Cloud CLI.

  4. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  5. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  7. Installa Google Cloud CLI.

  8. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  9. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init

Sfondo

Questo tutorial utilizza IAP per autenticare gli utenti. Questo è solo uno dei tanti approcci possibili. Per saperne di più sui vari metodi per autenticare gli utenti, consulta la sezione Concetti di autenticazione.

L'app Hello user-email-address

L'app per questo tutorial è un'app App Engine Hello World minima, con una funzionalità non tipica: anziché "Hello world" visualizza "Hello user-email-address", dove user-email-address è l'indirizzo email dell'utente autenticato.

Questa funzionalità è possibile esaminando le informazioni autenticate che IAP aggiunge a ogni richiesta web che passa alla tua app. A ogni richiesta web che raggiunge la tua app vengono aggiunte tre nuove intestazioni di richiesta. Le prime due intestazioni sono stringhe di testo normale che puoi utilizzare per identificare l'utente. La terza intestazione è un oggetto firmato in modo crittografico con le stesse informazioni.

  • X-Goog-Authenticated-User-Email: l'indirizzo email di un utente lo identifica. Non memorizzare informazioni personali se la tua app può evitarlo. Questa app non memorizza alcun dato, ma lo restituisce all'utente.

  • X-Goog-Authenticated-User-Id: questo ID utente assegnato da Google non mostra informazioni sull'utente, ma consente a un'app di sapere che l'utente che ha eseguito l'accesso è lo stesso visto in precedenza.

  • X-Goog-Iap-Jwt-Assertion: puoi configurare le app Google Cloud in modo che accettino richieste web da altre app cloud, bypassando IAP, oltre alle richieste web internet. Se un'app è configurata in questo modo, è possibile che queste richieste abbiano intestazioni falsificate. Anziché utilizzare una delle intestazioni di testo normale menzionate in precedenza, puoi utilizzare e verificare questa intestazione con firma crittografica per controllare che le informazioni siano state fornite da Google. L'indirizzo email dell'utente e un ID utente persistente sono disponibili nell'ambito di questa intestazione firmata.

Se hai la certezza che l'app sia configurata in modo che possa ricevere solo richieste web da internet e che nessuno possa disattivare il servizio IAP per l'app, il recupero di un ID utente univoco richiede una sola riga di codice:

$userId = getallheaders()['X-Goog-Authenticated-User-Id'] ?? null;

Tuttavia, un'app resiliente deve prevedere che le cose vadano male, inclusi problemi di configurazione o ambientali imprevisti, pertanto consigliamo di creare una funzione che utilizzi e verifichi l'intestazione firmata crittograficamente. La firma di questa intestazione non può essere falsificata e, una volta verificata, può essere utilizzata per restituire l'identificazione.

Crea il codice sorgente

  1. Utilizza un editor di testo per creare un file denominato index.php e incolla il seguente codice:

    require_once __DIR__ . '/vendor/autoload.php';
    
    /**
     * Checks that the JWT assertion is valid (properly signed, for the
     * correct audience) and if so, returns strings for the requesting user's
     * email and a persistent user ID. If not valid, returns null for each field.
     *
     * @param string $idToken The JWT string to assert.
     * @param string $audience The audience of the JWT.
     *
     * @return string[] array containing [$email, $id]
     * @throws Exception on failed validation
     */
    function validate_assertion(string $idToken, string $audience) : array
    {
        $auth = new Google\Auth\AccessToken();
        $info = $auth->verify($idToken, [
          'certsLocation' => Google\Auth\AccessToken::IAP_CERT_URL,
          'throwException' => true,
        ]);
    
        if ($audience != $info['aud'] ?? '') {
            throw new Exception(sprintf(
                'Audience %s did not match expected %s', $info['aud'], $audience
            ));
        }
    
        return [$info['email'], $info['sub']];
    }
    
    /**
     * This is an example of a front controller for a flat file PHP site. Using a
     * static list provides security against URL injection by default.
     */
    switch (@parse_url($_SERVER['REQUEST_URI'])['path']) {
        case '/':
            if (!Google\Auth\Credentials\GCECredentials::onGce()) {
                throw new Exception('You must deploy to appengine to run this sample');
            }
            $metadata = new Google\Cloud\Core\Compute\Metadata();
            $audience = sprintf(
                '/projects/%s/apps/%s',
                $metadata->getNumericProjectId(),
                $metadata->getProjectId()
            );
            $idToken = getallheaders()['X-Goog-Iap-Jwt-Assertion'] ?? '';
            try {
                list($email, $id) = validate_assertion($idToken, $audience);
                printf("<h1>Hello %s</h1>", $email);
            } catch (Exception $e) {
                printf('Failed to validate assertion: %s', $e->getMessage());
            }
            break;
        case '': break; // Nothing to do, we're running our tests
        default:
            http_response_code(404);
            exit('Not Found');
    }

    Questo file index.php è spiegato in dettaglio nella sezione Comprendere il codice più avanti in questo tutorial.

  2. Crea un altro file denominato composer.json e incolla al suo interno quanto segue:

    {
      "require": {
        "php": ">=7.1",
        "google/auth": "^1.9",
        "google/cloud-core": "^1.32",
        "kelvinmo/simplejwt": "^0.4.0"
      }
    }
    

    Il file composer.json elenca le librerie PHP che App Engine deve caricare per la tua app:

    • firebase/php-jwt fornisce la funzione di controllo e decodifica JWT.

    • guzzle/http è un client HTTP per il recupero di dati dai siti web.

  3. Crea un file denominato app.yaml e inserisci il seguente testo:

    runtime: php73
    

    Il file app.yaml indica ad App Engine l'ambiente di linguaggio richiesto dal tuo codice.

Nozioni di base sul codice

Questa sezione spiega come funziona il codice in index.php. Se vuoi solo eseguire l'app, puoi passare direttamente alla sezione Esegui il deployment dell'app.

Il seguente codice si trova nel file index.php. Quando l'app riceve una richiesta HTTP GET alla home page, viene richiamato il caso switch per /:

/**
 * This is an example of a front controller for a flat file PHP site. Using a
 * static list provides security against URL injection by default.
 */
switch (@parse_url($_SERVER['REQUEST_URI'])['path']) {
    case '/':
        if (!Google\Auth\Credentials\GCECredentials::onGce()) {
            throw new Exception('You must deploy to appengine to run this sample');
        }
        $metadata = new Google\Cloud\Core\Compute\Metadata();
        $audience = sprintf(
            '/projects/%s/apps/%s',
            $metadata->getNumericProjectId(),
            $metadata->getProjectId()
        );
        $idToken = getallheaders()['X-Goog-Iap-Jwt-Assertion'] ?? '';
        try {
            list($email, $id) = validate_assertion($idToken, $audience);
            printf("<h1>Hello %s</h1>", $email);
        } catch (Exception $e) {
            printf('Failed to validate assertion: %s', $e->getMessage());
        }
        break;
    case '': break; // Nothing to do, we're running our tests
    default:
        http_response_code(404);
        exit('Not Found');
}

L'istruzione switch recupera il valore dell'intestazione dell'asserzione JWT che IAP ha aggiunto dalla richiesta in entrata e chiama una funzione per convalidare il valore firmato crittograficamente. Il primo valore restituito (email) viene quindi utilizzato in una pagina web minimale che crea e restituisce.

/**
 * Checks that the JWT assertion is valid (properly signed, for the
 * correct audience) and if so, returns strings for the requesting user's
 * email and a persistent user ID. If not valid, returns null for each field.
 *
 * @param string $idToken The JWT string to assert.
 * @param string $audience The audience of the JWT.
 *
 * @return string[] array containing [$email, $id]
 * @throws Exception on failed validation
 */
function validate_assertion(string $idToken, string $audience) : array
{
    $auth = new Google\Auth\AccessToken();
    $info = $auth->verify($idToken, [
      'certsLocation' => Google\Auth\AccessToken::IAP_CERT_URL,
      'throwException' => true,
    ]);

    if ($audience != $info['aud'] ?? '') {
        throw new Exception(sprintf(
            'Audience %s did not match expected %s', $info['aud'], $audience
        ));
    }

    return [$info['email'], $info['sub']];
}

La funzione validate_assertion utilizza la libreria google/auth per verificare che l'asserzione sia firmata correttamente e per estrarre le informazioni sul payload dall'asserzione. Se l'asserzione non può essere decodificata, la funzione genera un'eccezione. Se l'operazione va a buon fine, la funzione restituisce l'indirizzo email dell'utente autenticato e un ID univoco persistente per l'utente.

La convalida di un'asserzione JWT richiede la conoscenza dei certificati di chiave pubblica dell'entità che ha firmato l'asserzione (Google in questo caso) e del pubblico a cui è destinata l'asserzione. Per un'app App Engine, il pubblico è una stringa con Google Cloud informazioni di identificazione del progetto. Questa funzione recupera questi certificati e la stringa del segmento di pubblico dalle funzioni precedenti.

$metadata = new Google\Cloud\Core\Compute\Metadata();
$audience = sprintf(
    '/projects/%s/apps/%s',
    $metadata->getNumericProjectId(),
    $metadata->getProjectId()
);

Puoi cercare l'ID numerico e il nome del progetto e inserirli nel codice sorgente, ma la funzione audience lo fa per te eseguendo una query sul servizio di metadati standard reso disponibile per ogni app App Engine. Google Cloud

Il servizio di metadati App Engine (e servizi di metadati simili per altri servizi di calcoloGoogle Cloud ) ha l'aspetto di un sito web e viene interrogato da query web standard. Tuttavia, non si tratta di un sito esterno, ma di una funzionalità interna che restituisce le informazioni richieste sull'app in esecuzione, quindi è sicuro utilizzare http anziché le richieste https. Viene utilizzato per ottenere gli identificatori Google Cloud correnti necessari per definire il pubblico previsto dell'asserzione JWT.

Deployment dell'app in corso

Ora puoi eseguire il deployment dell'app e poi attivare IAP per richiedere agli utenti di autenticarsi prima di poter accedere all'app.

  1. Nella finestra del terminale, vai alla directory contenente il file app.yaml ed esegui il deployment dell'app in App Engine:

    gcloud app deploy
    
  2. Quando richiesto, seleziona una regione nelle vicinanze.

  3. Quando ti viene chiesto se vuoi continuare con l'operazione di deployment, inserisci Y.

    Entro pochi minuti, la tua app sarà disponibile su internet.

  4. Visualizza l'app:

    gcloud app browse
    

    Nell'output, copia web-site-url, l'indirizzo web dell'app.

  5. In una finestra del browser, incolla web-site-url per aprire l'app.

    Non viene visualizzata alcuna email perché non utilizzi ancora IAP, quindi non vengono inviate informazioni utente all'app.

Abilitare IAP

Ora che esiste un'istanza App Engine, puoi proteggerla con IAP:

  1. Nella console Google Cloud , vai alla pagina Identity-Aware Proxy.

    Vai alla pagina Identity-Aware Proxy

  2. Poiché è la prima volta che abiliti un'opzione di autenticazione per questo progetto, visualizzi un messaggio che ti informa che devi configurare la schermata per il consenso OAuth prima di poter utilizzare IAP.

    Fai clic su Configura schermata di consenso.

  3. Nella scheda Schermata per il consenso OAuth della pagina Credenziali, compila i seguenti campi:

    • Se il tuo account si trova in un'organizzazione Google Workspace, seleziona Esterno e fai clic su Crea. All'inizio, l'app sarà disponibile solo per gli utenti che autorizzi esplicitamente.

    • Nel campo Nome applicazione, inserisci IAP Example.

    • Nel campo Email di assistenza, inserisci il tuo indirizzo email.

    • Nel campo Dominio autorizzato, inserisci la parte del nome host dell'URL dell'app, ad esempio iap-example-999999.uc.r.appspot.com. Premi il tasto Enter dopo aver inserito il nome host nel campo.

    • Nel campo Link alla home page dell'applicazione, inserisci l'URL della tua app, ad esempio https://iap-example-999999.uc.r.appspot.com/.

    • Nel campo Riga delle norme sulla privacy dell'applicazione, utilizza lo stesso URL del link alla home page a scopo di test.

  4. Fai clic su Salva. Quando ti viene chiesto di creare le credenziali, puoi chiudere la finestra.

  5. Nella console Google Cloud , vai alla pagina Identity-Aware Proxy.

    Vai alla pagina Identity-Aware Proxy

  6. Per aggiornare la pagina, fai clic su Aggiorna . La pagina mostra un elenco delle risorse che puoi proteggere.

  7. Nella colonna IAP, fai clic per attivare IAP per l'app.

  8. Nel browser, vai di nuovo a web-site-url.

  9. Al posto della pagina web, viene visualizzata una schermata di accesso per l'autenticazione. Quando accedi, l'accesso ti viene negato perché IAP non dispone di un elenco di utenti da autorizzare ad accedere all'app.

Aggiungere utenti autorizzati all'app

  1. Nella console Google Cloud , vai alla pagina Identity-Aware Proxy.

    Vai alla pagina Identity-Aware Proxy

  2. Seleziona la casella di controllo per l'app App Engine e poi fai clic su Aggiungi entità.

  3. Inserisci allAuthenticatedUsers, quindi seleziona il ruolo Cloud IAP/Utente applicazione web con protezione IAP.

  4. Fai clic su Salva.

Ora qualsiasi utente che Google può autenticare può accedere all'app. Se vuoi, puoi limitare ulteriormente l'accesso aggiungendo solo una o più persone o gruppi come entità di sicurezza:

  • Qualsiasi indirizzo email Gmail o Google Workspace

  • Un indirizzo email del gruppo Google

  • Un nome di dominio Google Workspace

Accedere all'app

  1. Nel browser, vai a web-site-url.

  2. Per aggiornare la pagina, fai clic su Aggiorna .

  3. Nella schermata di accesso, accedi con le tue credenziali Google.

    La pagina mostra il messaggio "Hello user-email-address" con il tuo indirizzo email.

    Se continui a visualizzare la stessa pagina di prima, potrebbe esserci un problema con il browser che non aggiorna completamente le nuove richieste ora che hai attivato IAP. Chiudi tutte le finestre del browser, riaprile e riprova.

Concetti di autenticazione

Esistono diversi modi in cui un'app può autenticare i propri utenti e limitare l'accesso solo agli utenti autorizzati. I metodi di autenticazione comuni, in ordine decrescente di impegno per l'app, sono elencati nelle sezioni seguenti.

Opzione Vantaggi Svantaggi
Autenticazione dell'app
  • L'app può essere eseguita su qualsiasi piattaforma, con o senza una connessione a internet
  • Gli utenti non devono utilizzare altri servizi per gestire l'autenticazione
  • L'app deve gestire le credenziali utente in modo sicuro e proteggerle dalla divulgazione.
  • L'app deve mantenere i dati di sessione per gli utenti che hanno eseguito l'accesso
  • L'app deve fornire registrazione utente, modifiche della password e recupero della password
OAuth2
  • L'app può essere eseguita su qualsiasi piattaforma connessa a internet, inclusa una workstation per sviluppatori
  • L'app non richiede la registrazione dell'utente, modifiche della password o funzioni di recupero della password.
  • Il rischio di divulgazione delle informazioni dell'utente viene delegato a un altro servizio
  • Nuove misure di sicurezza per l'accesso gestite al di fuori dell'app
  • Gli utenti devono registrarsi al servizio di identità
  • L'app deve mantenere i dati di sessione per gli utenti che hanno eseguito l'accesso
IAP
  • L'app non deve avere alcun codice per gestire utenti, autenticazione o stato della sessione
  • L'app non dispone di credenziali utente che potrebbero essere violate
  • L'app può essere eseguita solo su piattaforme supportate dal servizio. Nello specifico, alcuni servizi Google Cloud che supportano IAP, come App Engine.

Autenticazione gestita dall'app

Con questo metodo, l'app gestisce autonomamente ogni aspetto dell'autenticazione utente. L'app deve gestire un proprio database di credenziali utente e gestire le sessioni utente e deve fornire funzioni per gestire account utente e password, controllare le credenziali utente, nonché emettere, controllare e aggiornare le sessioni utente a ogni accesso autenticato. Il seguente diagramma illustra il metodo di autenticazione gestito dall'app.

Flusso gestito dall&#39;applicazione

Come mostrato nel diagramma, dopo l'accesso dell'utente, l'app crea e gestisce le informazioni sulla sessione dell'utente. Quando l'utente effettua una richiesta all'app, la richiesta deve includere le informazioni sulla sessione che l'app è responsabile di verificare.

Il vantaggio principale di questo approccio è che è autonomo e sotto il controllo dell'app. L'app non deve nemmeno essere disponibile su internet. Lo svantaggio principale è che l'app è ora responsabile di fornire tutte le funzionalità di gestione dell'account e di proteggere tutti i dati sensibili delle credenziali.

Autenticazione esterna con OAuth2

Una buona alternativa alla gestione di tutto all'interno dell'app è l'utilizzo di un servizio di identità esterno, come Google, che gestisce tutte le informazioni e le funzionalità dell'account utente ed è responsabile della salvaguardia delle credenziali sensibili. Quando un utente tenta di accedere all'app, la richiesta viene reindirizzata al servizio di identità, che autentica l'utente e poi reindirizza la richiesta all'app con le informazioni di autenticazione necessarie. Per saperne di più, consulta l'articolo sull'utilizzo di OAuth 2.0 per applicazioni server web.

Il seguente diagramma illustra l'autenticazione esterna con il metodo OAuth2.

Flusso OAuth2

Il flusso nel diagramma inizia quando l'utente invia una richiesta di accesso all'app. Invece di rispondere direttamente, l'app reindirizza il browser dell'utente alla piattaforma per la gestione delle identità di Google, che mostra una pagina per accedere a Google. Dopo aver eseguito l'accesso, il browser dell'utente viene reindirizzato all'app. Questa richiesta include informazioni che l'app può utilizzare per cercare informazioni sull'utente ora autenticato e l'app ora risponde all'utente.

Questo metodo presenta molti vantaggi per l'app. Delega tutte le funzionalità e i rischi di gestione dell'account al servizio esterno, il che può migliorare la sicurezza dell'accesso e dell'account senza che l'app debba essere modificata. Tuttavia, come mostrato nel diagramma precedente, l'app deve avere accesso a internet per utilizzare questo metodo. L'app è anche responsabile della gestione delle sessioni dopo l'autenticazione dell'utente.

Identity-Aware Proxy

Il terzo approccio, trattato in questo tutorial, consiste nell'utilizzare IAP per gestire tutta l'autenticazione e la gestione delle sessioni con eventuali modifiche all'app. IAP intercetta tutte le richieste web alla tua app, blocca quelle che non sono state autenticate e le altre le fa passare con i dati dell'identità utente aggiunti a ogni richiesta.

La gestione delle richieste è illustrata nel seguente diagramma.

Flusso IAP

Le richieste degli utenti vengono intercettate da IAP, che blocca le richieste non autenticate. Le richieste autenticate vengono trasmesse all'app, a condizione che l'utente autenticato sia presente nell'elenco degli utenti consentiti. Le richieste passate tramite IAP hanno intestazioni aggiunte che identificano l'utente che ha effettuato la richiesta.

L'app non deve più gestire account utente o informazioni sulla sessione. Qualsiasi operazione che deve conoscere un identificatore univoco per l'utente può ottenerlo direttamente da ogni richiesta web in entrata. Tuttavia, può essere utilizzato solo per i servizi di computing che supportano IAP, come App Engine e i bilanciatori del carico. Non puoi utilizzare IAP su una macchina di sviluppo locale.

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

  1. Nella console Google Cloud , vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona quello che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Passaggi successivi