書評とWEB開発の情報を中心にお届けします。

firebaseでexpressを公開する⑧firestoreでログイン可能なアカウントを制御する

概要

前回、firebase authenticationによるログインを実装しました。
しかし、firebase authenticationのメールアドレスユーザーは誰もが自由にアカウントを作ることが可能です。
つまり、誰でもログインが出来てしまうのです。
管理画面のような特定のユーザーしかアクセスできないサイトを作る場合、さらに設定が必要です。

今回は、firebase firestoreを使い、authenticationに登録されているユーザーの中でもfirestoreに登録されているものだけをログイン可能にしてみます。

firestoreにデータを登録

authenticationに登録されているアカウントのuidをコピーし、それをfirestoreに登録します。

f:id:necrates:20191128171637p:plain

なぜemailで管理をしないかというと、firebase authenticationのemailは変更が可能なため、変更された後にログイン不可となってしまうのを防ぐためです。

functionsからfirestoreに接続する

functionsからfirestoreに接続する場合、Firebase Admin SDK秘密鍵が必要になるため(※)、firebaseのコンソールからダウンロードしておいてください。

※ functionsがdeployされている状態で同じプロジェクトのfirestoreに接続する分には必要なさそうなのですが、firebase serve --only functinosで動かすためには必要です。

ダウンロードした秘密鍵/functions/serviceAccountKet.json として配置します。

/functions/index.jsを以下のように修正します。

const functions = require('firebase-functions');
const admin = require("firebase-admin");
const serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://[プロジェクトID].firebaseio.com"
});

const expressApp = require('./express/index.js');

module.exports.express = functions.https.onRequest(expressApp);

/functions/express/index.jsの認証部分を修正します。

const firestore = require("firebase-admin").firestore();

~~~~~~~~~~~~~~~~~~~~

passport.use(new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password',
  passReqToCallback: true,
  session: false,
}, (req, email, password, done) => {
  firebase.auth().signInWithEmailAndPassword(email, password)
  .then((d) => {
    return firestore.collection("admin").doc(d.user.uid).get();
  })
  .then((doc) => {
    if (doc.exists) return done(null, { uid: doc.id, email: email });
    throw new Error();
  })
  .catch((e) => {
    return done(null, false);
  });
}));

ログインの流れとしては、先ずemail/passwordでログイン処理を行う。 ログインが出来たら、そのユーザーがfirestoreに登録されているかを確認する。 どこかに問題があればログイン失敗とする。

動作確認

前回作ったユーザーとは別に新たにユーザーを作り、firestoreに登録されているものだけがログインできれば正常です。