ユーザーの認証

Firebase Authentication を使用するウェブサービスにユーザー ログイン フローを追加します。

本ガイドのこのステップでは、ウェブサービスを更新してユーザーを認証し、認証後にユーザー固有の情報を取得して表示します。このステップでは、サイト リクエスト時間はユーザー固有ではなくグローバルのままであるので注意してください。

始める前に

このガイドでこれまでのステップをすべて完了している場合は、このセクションをスキップできます。それ以外の場合は、次のいずれかを実行してください。

  • Python 3.7 アプリのビルドから始めて、ここまでのステップをすべて完了します。

  • GCP プロジェクトがすでにある場合は、次のようにウェブサービスのコピーをダウンロードして Firebase を追加すれば、これ以降の処理を続行できます。

    1. Git を使用してサンプル アプリケーション リポジトリをダウンロードします。

      git clone https://github.com/GoogleCloudPlatform/python-docs-samples
      

      または、zip 形式のサンプルをダウンロードして展開します。

    2. 前のステップで用意したファイルのコピーがあるディレクトリに移動します。

      cd python-docs-samples/appengine/standard_python37/building-an-app/building-an-app-2
      
    3. GCP プロジェクトとウェブサービスに Firebase を追加します。

Firebase 認証メソッドを追加する

Firebase は、ウェブサービスのログイン動作を構成するために使用できる JavaScript のメソッドと変数を提供します。このウェブサービスでは、ログアウト関数、ログイン UI を構成する変数、ユーザーがログインまたはログアウトするときの変更を制御する関数を追加します。

認証フローに必要な動作を追加するには、static/script.js ファイルの現在のイベント リスナー メソッドを次のコードに置き換えます。

window.addEventListener('load', function () {
  document.getElementById('sign-out').onclick = function () {
    firebase.auth().signOut();
  };

  // FirebaseUI config.
  var uiConfig = {
    signInSuccessUrl: '/',
    signInOptions: [
      // Comment out any lines corresponding to providers you did not check in
      // the Firebase console.
      firebase.auth.GoogleAuthProvider.PROVIDER_ID,
      firebase.auth.EmailAuthProvider.PROVIDER_ID,
      //firebase.auth.FacebookAuthProvider.PROVIDER_ID,
      //firebase.auth.TwitterAuthProvider.PROVIDER_ID,
      //firebase.auth.GithubAuthProvider.PROVIDER_ID,
      //firebase.auth.PhoneAuthProvider.PROVIDER_ID

    ],
    // Terms of service url.
    tosUrl: '<your-tos-url>'
  };

  firebase.auth().onAuthStateChanged(function (user) {
    if (user) {
      // User is signed in, so display the "sign out" button and login info.
      document.getElementById('sign-out').hidden = false;
      document.getElementById('login-info').hidden = false;
      console.log(`Signed in as ${user.displayName} (${user.email})`);
      user.getIdToken().then(function (token) {
        // Add the token to the browser's cookies. The server will then be
        // able to verify the token against the API.
        // SECURITY NOTE: As cookies can easily be modified, only put the
        // token (which is verified server-side) in a cookie; do not add other
        // user information.
        document.cookie = "token=" + token;
      });
    } else {
      // User is signed out.
      // Initialize the FirebaseUI Widget using Firebase.
      var ui = new firebaseui.auth.AuthUI(firebase.auth());
      // Show the Firebase login button.
      ui.start('#firebaseui-auth-container', uiConfig);
      // Update the login state indicators.
      document.getElementById('sign-out').hidden = true;
      document.getElementById('login-info').hidden = true;
      // Clear the token cookie.
      document.cookie = "token=";
    }
  }, function (error) {
    console.log(error);
    alert('Unable to log in: ' + error)
  });
});

ユーザーがログインまたはログアウトしたときの変更を制御する onAuthStateChanged() メソッドは、ユーザーの ID トークンを Cookie として格納します。この ID トークンは、ユーザーがログインに成功したとき Firebase が自動的に生成する一意のトークンであり、ユーザーを認証するためにサーバーによって使用されます。

ヒント: 利用規約の URL は省略可能です。

トークンを使用するためにウェブサービスを更新する

次に、一意の Firebase ID トークンを使用してサーバーでユーザーを検証してから、ユーザーのデータをユーザーに表示できるようにトークンを復号します。

Firebase ID トークンを使用するには:

  1. main.py ファイルの root メソッドでトークンの取得、検証、復号を行います。

    from flask import Flask, render_template, request
    from google.auth.transport import requests
    from google.cloud import datastore
    import google.oauth2.id_token
    
    firebase_request_adapter = requests.Request()
    @app.route('/')
    def root():
        # Verify Firebase auth.
        id_token = request.cookies.get("token")
        error_message = None
        claims = None
        times = None
    
        if id_token:
            try:
                # Verify the token against the Firebase Auth API. This example
                # verifies the token on each page load. For improved performance,
                # some applications may wish to cache results in an encrypted
                # session store (see for instance
                # http://flask.pocoo.org/docs/1.0/quickstart/#sessions).
                claims = google.oauth2.id_token.verify_firebase_token(
                    id_token, firebase_request_adapter)
            except ValueError as exc:
                # This will be raised if the token is expired or any other
                # verification checks fail.
                error_message = str(exc)
    
            # Record and fetch the recent times a logged-in user has accessed
            # the site. This is currently shared amongst all users, but will be
            # individualized in a following step.
            store_time(datetime.datetime.now())
            times = fetch_times(10)
    
        return render_template(
            'index.html',
            user_data=claims, error_message=error_message, times=times)

    ヒント: Flask から request をインポートして、ユーザーの ID トークンを含む Cookie をフェッチできるようにしてください。

  2. requirements.txt ファイルに必要な依存関係がすべて含まれていることを確認します。

    Flask==1.0.2
    google-cloud-datastore==1.7.3
    google-auth==1.6.2
    requests==2.21.0
    

ウェブサービスをテストする

virtualenv を使用して依存関係を処理し、ウェブサービスをローカルで実行してテストします。

  1. プロジェクトのメイン ディレクトリで次のコマンドを実行して、新しい依存関係をインストールし、ウェブサービスを実行します。ローカルテスト用に virtualenv を設定していない場合は、ウェブサービスのテストを参照してください。

    pip install -r requirements.txt
    python main.py
    
  2. ウェブサービスを表示するには、ウェブブラウザに次のアドレスを入力します。

    http://localhost:8080
    

ウェブサービスをデプロイする

以上でローカルでの認証を設定できたので、ウェブサービスを App Engine に再デプロイできます。

app.yaml ファイルが置かれているプロジェクトのルート ディレクトリから、次のコマンドを実行します。

gcloud app deploy

すべてのトラフィックは、デプロイした新しいバージョンに自動的にルーティングされます。

バージョン管理の詳細については、サービスとバージョンの管理をご覧ください。

サービスを表示する

ブラウザを速やかに起動して https://GCP_PROJECT_ID.appspot.com でウェブサービスにアクセスするには、次のコマンドを実行します。

gcloud app browse

次のステップ

以上でユーザー認証の設定が完了しました。次は、ウェブサービスを更新して認証済みユーザーのデータをパーソナライズする方法を学習します。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Python 3 の App Engine スタンダード環境