Firestoreセキュリティルールで認証有無によってアクセス権限を制御する


0. 始めに

(本記事は、拙作 Firestoreセキュリティルールを設定してみる の続きになっています!)
今回は認証情報を絡めてたルールを設定してみます!

0.Firestoreセキュリティルールを読み解く ← 前回
1.Firestoreセキュリティルールを設定してみる ← 前回
2.Firestoreセキュリティルールで認証有無によってアクセス権限を制御する ← 今回★

1. 準備

 毎度のことながら、以下が作業環境です1

 OS : Windows10 Home
 Node : v11.13.0
 yarn : v1.22.10

事前にFirebaseコンソールからプロジェクトの作成も行います。
環境の用意やFirebaseプロジェクト作成については述べませんが、詳しくはこちらを(宣伝)。
Firebaseでデプロイしよう!

2. モデルとなるサイトの用意

2.1 認証を行うフォームとFirestoreのデータを表示する画面の作成

 前回の「Firestoreセキュリティルールを設定してみる」で使用したサイトをベースに改修を加えます。
フォームの上部にログイン/ログアウトボタンをセットしています、相変わらず酷い質素なUIです(笑)。

ソースこんな感じ、認証機能を使うため<script src="https://www.gstatic.com/firebasejs/7.22.0/firebase-auth.js"></script>の一文が必要です。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>firestore-otameshi</title>
</head>
<body>
    <div class="auth">
        <button type="button" onclick="logIn()">ログイン</button>
        <button type="button" onclick="logOut()">ログアウト</button>
    </div>
    <form action="submit">
        <input id="addData" type="text">
    </form>
    <button type="button" onclick="addData()">送信</button>
    <button type="button" onclick="getData()">更新</button>
    <h5>Firestore-dataList</h5>
    <div id="dataList"></div>

    <script src="https://www.gstatic.com/firebasejs/7.22.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.22.0/firebase-firestore.js"></script>
    <!-- ★ ↓ 新しく追加したscript ★ -->
    <script src="https://www.gstatic.com/firebasejs/7.22.0/firebase-auth.js"></script>
    <!-- ★ ↑ 新しく追加したscript ★ -->
    <script src="./index.js"></script>
    <script src="./config.js"></script>
</body>
</html>

2.2 認証機能の実装

続いてjavascript側では、firestore側にデータを読み書きする処理と、emailとパスワードで認証2する処理を実装します。

index.js
// 受け取ったHTMLを表示
dispData = (html) => {
    document.querySelector("#dataList").innerHTML = html
}

// フォームのデータをfirestoreに追加
addData = () => {
    const inputData = document.getElementById("addData")

    if (!inputData.value) return
    firebase.firestore().collection("dataList").add({
        text: inputData.value
    })
    .then(() => {
        console.log("success!")
    })
    .catch((error) => {
        dispData(`データの追加に失敗しました (${error})`)
    })
}

// firestoreからデータを取得
getData = () => {
    firebase.firestore().collection("dataList").get().then((querySnapshot) => {
        let html = "<ul>"
        querySnapshot.forEach((doc) => {
            const data = doc.data()
            html += `<li>${data.text}</li>`
        })
        html += "</ul>"

        dispData(html)
    })
    .catch((error)=> {
        dispData(`データの取得に失敗しました (${error})`)
    })
}

/* 
 認証機能
*/
// 認証情報(固定値)でログインを行う
logIn = async() => {
    const UserData = {
        email: "[email protected]",
        passWord: "xxxxxxxxxxxxxxxxxxxxxx"
    }
    const {email, passWord} = UserData
    try {
        await firebase.auth().signInWithEmailAndPassword(email, passWord)
        alert("successfully login")
    } catch(error) {
        alert(error)
    }
}

// ログアウトをする
logOut = () => {
    firebase.auth().signOut()
    alert("successfully logout")
}

3. 認証有無を判定する

 firestoreルールを以下のように設定して、ログインしていないとDBへ登録できないようにします

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /dataList/{data} {
      allow read: if true;
      allow write: if request.auth.uid != null;
    }
  }
}

ログインしていない状態で送信ボタンを押しても、権限で弾かれて登録出来ていない事が確認できます。

終わりに

実際のアプリでは、認証情報によってルーティングとかもしないといけないので、認証部分はこんな単純な話ではないです。
まぁ、お試しでやる分には問題ないかなといった感じですね。

参考

1.[Firebase] Firestoreで読み書きする (Web編)


  1. デプロイ(サイトを公開)しない場合は、Node, yarnは不要です。 

  2. 2020/10/23 現在、emailとパスワードを使用した認証方法は脆弱性が確認されています(https://medium.com/swlh/google-firebase-authentication-vulnerability-245050cb7ceb)。 今回のようにセキュリティルールが正しく設定されている事の確認のみだったら問題ないでしょうが、実際のアプリケーションには導入しない事をオススメします。