高度な認証機能

1. セットアップ

ソースコードを取得する

この Codelab では、ほぼ完成したバージョンの Friendly Chat サンプルアプリを使用します。まず、ソースコードを複製する必要があります。

$ git clone https://github.com/firebase/codelab-friendlychat-web --branch security

次に、security-start ディレクトリに移動します。この Codelab の残りの作業は、このディレクトリで行います。

$ cd codelab-friendlychat-web/security-start

次に、コードを実行できるように依存関係をインストールします。インターネット接続が遅い場合は、1 ~ 2 分ほどかかることがあります。

$ npm install && (cd functions && npm install)

このリポジトリについて

security-solution/ ディレクトリには、サンプルアプリの完全なコードが含まれています。security-start ディレクトリは、Codelab で作業する場所であり、認証実装の重要な部分がいくつか欠落しています。security-start/security-solution/ の重要なファイルと機能は次のとおりです。

  • functions/index.js には Cloud Functions のコードが含まれており、認証ブロック関数を記述します。
  • public/ - Chat 用アプリの静的ファイルが格納されます
  • public/scripts/main.js - Chat 用アプリの JS コード(src/index.js)がコンパイルされる場所
  • src/firebase-config.js - チャットアプリの初期化に使用される Firebase 構成オブジェクトが含まれています
  • src/index.js - Chat 用アプリの JavaScript コード

Firebase CLI を取得する

Emulator Suite は Firebase CLI(コマンドライン インターフェース)の一部です。次のコマンドを使用して、マシンにインストールできます。

$ npm install -g firebase-tools@latest

webpack で JavaScript をビルドします。これにより、public/scripts/ ディレクトリ内に main.js が作成されます。

webpack build

次に、CLI の最新バージョンを使用していることを確認します。この Codelab はバージョン 11.14 以降で動作します。

$ firebase --version
11.14.2

Firebase プロジェクトに接続する

新しい Firebase プロジェクトを作成

  1. Google アカウントを使用して Firebase コンソールにログインします。
  2. ボタンをクリックして新しいプロジェクトを作成し、プロジェクト名(例: Authentication MFA Codelab)を入力します。
  3. [続行] をクリックします。
  4. Firebase の利用規約が表示されたら、内容を読み、同意して [続行] をクリックします。
  5. (省略可)Firebase コンソールで AI アシスタンス(「Gemini in Firebase」)を有効にします。
  6. この Codelab では Google アナリティクスは必要ないため、Google アナリティクスのオプションをオフに切り替えます
  7. [プロジェクトを作成] をクリックし、プロジェクトのプロビジョニングが完了するまで待ってから、[続行] をクリックします。

コードを Firebase プロジェクトに接続する

次に、このコードを Firebase プロジェクトに接続する必要があります。まず、次のコマンドを実行して Firebase CLI にログインします。

$ firebase login

次に、次のコマンドを実行してプロジェクト エイリアスを作成します。$YOUR_PROJECT_ID は、Firebase プロジェクトの ID に置き換えます。

$ firebase use $YOUR_PROJECT_ID

これで、アプリを実行する準備が整いました。

2. エミュレータを実行する

このセクションでは、アプリをローカルで実行します。Emulator Suite を起動するタイミングです。

エミュレータを起動する

コードラボのソース ディレクトリ内で、次のコマンドを実行してエミュレータを起動します。

$ firebase emulators:start

これにより、アプリが http://127.0.0.1:5170 で提供され、変更を加えるたびにソースコードが継続的に再ビルドされます。変更を確認するには、ブラウザでローカルにハード更新(Ctrl+Shift+R)するだけで済みます。

次のような出力が表示されます。

i  emulators: Starting emulators: auth, functions, firestore, hosting, storage
✔  functions: Using node@16 from host.
i  firestore: Firestore Emulator logging to firestore-debug.log
✔  firestore: Firestore Emulator UI websocket is running on 9150.
i  hosting[demo-example]: Serving hosting files from: ./public
✔  hosting[demo-example]: Local server: http://127.0.0.1:5170
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "[...]" for Cloud Functions...
✔  functions: Loaded functions definitions from source: beforecreated.
✔  functions[us-central1-beforecreated]: providers/cloud.auth/eventTypes/user.beforeCreate function initialized (http://127.0.0.1:5011/[...]/us-central1/beforecreated).
i  Running script: npm start
 
> security@1.0.0 start
> webpack --watch --progress
[...]
webpack 5.50.0 compiled with 1 warning in 990 ms

[All emulators ready](すべてのエミュレータの準備が完了しました)というメッセージが表示されたら、アプリを使用できます。

3. MFA の実装

このリポジトリには MFA が部分的に実装されています。まず、ユーザーを MFA に登録するコードを追加し、次に、MFA に登録したユーザーに第 2 要素の入力を求めるコードを追加します。

エディタで src/index.js ファイルを開き、startEnrollMultiFactor() メソッドを見つけます。次のコードを追加して、電話番号の不正使用を防ぐ reCAPTCHA ベリファイアを設定します(reCAPTCHA ベリファイアは非表示に設定され、ユーザーには表示されません)。

async function startEnrollMultiFactor(phoneNumber) {
  const recaptchaVerifier = new RecaptchaVerifier(
    "recaptcha",
    { size: "invisible" },
    getAuth()
  );

次に、finishEnrollMultiFactor() メソッドを見つけて、次のコードを追加して 2 段階認証プロセスを登録します。

// Completes MFA enrollment once a verification code is obtained.
async function finishEnrollMultiFactor(verificationCode) {
  // Ask user for the verification code. Then:
  const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
  const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
 
  // Complete enrollment.
  await multiFactor(getAuth().currentUser)
    .enroll(multiFactorAssertion)
    .catch(function (error) {
      alert(`Error finishing second factor enrollment. ${error}`);
      throw error;
    });
  verificationId = null;
}

次に、signIn 関数を見つけて、MFA に登録しているユーザーに第 2 要素の入力を求める次の制御フローを追加します。

async function signIn() {
  // Sign in Firebase using popup auth and Google as the identity provider.
  var provider = new GoogleAuthProvider();
  await signInWithPopup(getAuth(), provider)
    .then(function (userCredential) {
      // User successfully signed in and is not enrolled with a second factor.
    })
    .catch(function (error) {
      if (error.code == "auth/multi-factor-auth-required") {
        multiFactorResolver = getMultiFactorResolver(getAuth(), error);
        displaySecondFactor(multiFactorResolver.hints);
      } else {
        alert(`Error signing in user. ${error}`);
      }
    });
}

ここで呼び出される関数を含む残りの実装はすでに完了しています。動作を確認するには、ファイルの残りの部分を参照してください。

4. エミュレータで MFA を使用したログインを試す

MFA の実装を試してみましょう。エミュレータがまだ実行されていることを確認し、localhost:5170 でローカルでホストされているアプリにアクセスします。ログインを試すと、MFA コードの入力を求められます。ターミナル ウィンドウに MFA コードが表示されます。

エミュレータは多要素認証を完全にサポートしているため、開発環境を完全に自己完結型にすることができます。

MFA の実装の詳細については、リファレンス ドキュメントをご覧ください。

5. ブロッキング関数を作成する

一部のアプリケーションは、特定のユーザー グループのみが使用することを想定しています。このような場合、ユーザーがアプリに登録またはログインするためのカスタム要件を作成できるようにする必要があります。

ブロッキング関数は、カスタム認証要件を作成する方法を提供します。これらは Cloud Functions ですが、ほとんどの関数とは異なり、ユーザーが登録またはログインしようとすると同期的に実行されます。

ブロッキング関数を作成するには、エディタで functions/index.js を開き、コメントアウトされた beforecreated 関数を見つけます。

このコードに置き換えると、example.com ドメインのユーザーのみがアカウントを作成できるようになります。

exports.beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  // Only users of a specific domain can sign up.
  if (!user.email || !user.email.endsWith("@example.com")) {
    throw new HttpsError("invalid-argument", "Unauthorized email");
  }
});

6. エミュレータでブロッキング関数を試す

ブロック機能を試すには、エミュレータが実行されていることを確認し、localhost:5170 のウェブアプリでログアウトします。

次に、末尾が example.com ではないメールアドレスでアカウントを作成してみてください。ブロッキング関数により、オペレーションは成功しません。

今度は、末尾が example.com のメールアドレスでもう一度お試しください。アカウントが正常に作成されます。

ブロッキング関数を使用すると、認証に関する必要な制限を作成できます。詳細については、リファレンス ドキュメントをご覧ください。

内容のまとめ

その調子です!ユーザーがアカウントを安全に保てるように、ウェブアプリに多要素認証を追加しました。その後、ブロッキング関数を使用して、ユーザーが登録するためのカスタム要件を作成しました。GIF を獲得しました。

オフィスで「raise the roof」ダンスをする人々の GIF