Authenticating users with PHP

This part of the PHP Bookshelf app tutorial shows how to create a sign-in flow for users and how to use profile information to provide users with personalized features.

By using Google Identity Platform, you can access information about your users while ensuring their sign-in credentials are safely managed by Google. OAuth 2.0 provides a sign-in flow for all users of your app and provides your app access to basic profile information about authenticated users.

This page is part of a multipage tutorial. To start from the beginning and read the setup instructions, go to PHP Bookshelf app.

Creating a web app client ID

A web app client ID lets your app authorize users and access Google APIs.

  1. In the Google Cloud Platform Console, go to the Credentials page.

    Go to the Credentials page

  2. Click OAuth consent screen.

  3. In the Application name field, enter PHP Bookshelf App.

  4. In the Authorized domains field, enter your App Engine app name as [YOUR_PROJECT_ID].appspot.com. Replace [YOUR_PROJECT_ID] with the name of your GCP project ID.

  5. Fill in any other relevant, optional fields, and then click Save.

  6. Click Create credentials > OAuth client ID.

  7. Under Application type, select the Web application option.

  8. In the Name field, enter PHP Bookshelf Client.

  9. In the Authorized redirect URIs field, enter the following URLs, one at a time:

    http://localhost:8000/login/callback
    http://[YOUR_PROJECT_ID].appspot.com/login/callback
    https://[YOUR_PROJECT_ID].appspot.com/login/callback

  10. Click Create.

  11. Copy the client ID and client secret for later use.

Configuring settings

  1. Copy your settings.yml file from the Cloud Storage part of this tutorial to the getting-started-php/4-auth directory.

  2. In the copied file, replace [YOUR_CLIENT_ID] and [YOUR_CLIENT_SECRET] with the client ID and client secret you created previously.

Installing dependencies

In the 4-auth directory, enter this command:

composer install

Running the app on your local machine

  1. Start a local web server:

    php -S localhost:8000 -t web
    
  2. In your web browser, enter this address.

    http://localhost:8000

Now you can browse the app's web pages, sign in using your Google account, add books, and see the books you've added using the My Books link in the top navigation bar.

Deploying the app to the App Engine flexible environment

  1. In your terminal window, deploy the sample app:

    gcloud app deploy
    
  2. In your web browser, enter this address. Replace [YOUR_PROJECT_ID] with your GCP project ID:

    https://[YOUR_PROJECT_ID].appspot.com
    

    If you update your app, you can deploy the updated version by entering the same command you used when you first deployed the app. The new deployment creates a version of your app and promotes it to the default version.

    The older versions of your app remain, as do their associated virtual machine (VM) instances. Be aware that all of these app versions and VM instances are billable resources.

    You can reduce costs by deleting the non-default versions of your app.

    To delete an app version:

    1. In the GCP Console, go to the Versions page for App Engine.

      Go to the Versions page

    2. Select the checkbox for the non-default app version you want to delete.
    3. Click Delete to delete the app version.

    For complete information about cleaning up billable resources, see the Cleaning up section in the final step of this tutorial.

    App structure

    The following diagram shows the app's components and how they fit together.

    Auth sample structure

    Understanding the code

    The PHP session

    This tutorial uses PHP's native session management and memcache to persist a user's session. The PHP runtime is configured by default to use memcache for session configuration. This setup lets you use the Silex SessionServiceProvider service to manage a user's data during a session. Users sign in with their Google Account, and Google stores their basic data in the session:

    $app->register(new SessionServiceProvider);
    // fall back on PHP's "session.save_handler" for session storage
    $app['session.storage.handler'] = null;
    $app['user'] = function ($app) {
        /** @var Symfony\Component\HttpFoundation\Session\Session $session */
        $session = $app['session'];
    
        return $session->has('user') ? $session->get('user') : null;
    };

    The Google API PHP Client Library

    The Google API PHP Client Library provides OAuth functions that authenticate users who use a Google Account. To use these functions, you need to create the Google\Client service class and configure it for your app:

    $app['google_client'] = function ($app) {
        /** @var Symfony\Component\Routing\Generator\UrlGenerator $urlGen */
        $urlGen = $app['url_generator'];
        $redirectUri = $urlGen->generate('login_callback', [], $urlGen::ABSOLUTE_URL);
        return new Google_Client([
            'client_id'     => $app['config']['google_client_id'],
            'client_secret' => $app['config']['google_client_secret'],
            'redirect_uri'  => $redirectUri,
        ]);
    };

    When the user clicks Log in, the GET '/login' action uses the Google API PHP Client service class to generate the authorization URL and redirect the request:

    $app->get('/login', function () use ($app) {
        /** @var Google_Client $client */
        $client = $app['google_client'];
    
        $scopes = [ \Google_Service_Oauth2::USERINFO_PROFILE ];
        $authUrl = $client->createAuthUrl($scopes);
    
        return $app->redirect($authUrl);
    })->bind('login');

    The redirect_uri passed to the Google\Client service class is called when the user clicks Allow. This action receives an authorization code, which is used to get an access token. The token data is then stored in the session, and the user is redirected to the home page:

    $app->get('/login/callback', function () use ($app) {
        /** @var Request $request */
        $request = $app['request'];
    
        if (!$code = $request->query->get('code')) {
            return new Response('Code required', Response::HTTP_BAD_REQUEST);
        }
    
        /** @var Google_Client $client */
        $client = $app['google_client'];
        $authResponse = $client->fetchAccessTokenWithAuthCode($code);
    
        if ($client->getAccessToken()) {
            $userInfo = $client->verifyIdToken();
    
            /** @var Symfony\Component\HttpFoundation\Session\Session $session */
            $session = $app['session'];
            $session->set('user', [
                'id'      => $userInfo['sub'],
                'name'    => $userInfo['name'],
                'picture' => $userInfo['picture'],
            ]);
    
            return new Response('', Response::HTTP_FOUND, ['Location' => '/']);
        }
    
        // an error occured while trying to authorize - display it
        return new Response($authResponse['error_description'], 400);
    })->bind('login_callback');

    When the user signs out, the '/logout' action clears the user's information from the session:

    $app->get('/logout', function () use ($app) {
        /** @var Symfony\Component\HttpFoundation\Session\Session $session */
        $session = $app['session'];
        $session->remove('user');
    
        return new Response('', Response::HTTP_FOUND, ['Location' => '/']);
    })->bind('logout');

    Useful information about a user, such as their name and picture, is available after a user is authenticated. If the user is signed in, you can display that information in the base template. If no user information exists, you can display a Login button:

    {% if app.user %}
      {% if app.user.picture %}
        <img src="{{ app.user.picture }}" class="img-circle" width="24" alt="Photo" />
      {% endif %}
      <span>
        {{ app.user.name }} &nbsp;
        <a href="/logout">(logout)</a>
      </span>
    {% else %}
      <a href="/login">Login</a>
    {% endif %}
Czy ta strona była pomocna? Podziel się z nami swoją opinią:

Wyślij opinię na temat...