📊

Streamlit with Google Cloud: Firebase 認証

2023/02/27に公開1

前回に引き続き、今回は Streamlit アプリケーションに、Firebase 認証によるログイン機能を実装し、Cloud Run で動かしてみます。

この連載では、Google Cloud 上で Streamlit を上手に動かす方法をご紹介しています。


Firebase プロジェクトを準備する

1. プロジェクトを追加

https://console.firebase.google.com/ で「プロジェクトを作成」をクリック。

プロジェクトは選択肢の中からクラウドに用意したプロジェクト名を選択して、続行。

プランを確認、続行と進みます。「このプロジェクトで Google アナリティクスを有効にする」の選択肢を外しつつ「Firebase を追加」します。

「新しいプロジェクトの準備ができました」と表示されたら「続行」してください。

2. プロジェクトにウェブアプリ追加

HTML タグのアイコンをクリックして、ウェブアプリの追加を開始します。

任意の名前を指定したら「アプリを登録」し「コンソールに進む」

以下の画面になったら「Authentication」をクリックします。

「始める」をクリックして、「メール / パスワード」を選択、有効にして保存します。


「Users」タブに切りかえ、任意のユーザーを一人追加してみましょう。

3. ウェブアプリの SDK 設定値を取得

画面左上の歯車アイコンから「プロジェクトの設定」を選び、下図右側の設定がみえるところまでスクロールします。

画面の firebaseConfig の値を参考に、以下の形式で config.py として保存します。

config.py
firebase = {
  "apiKey": "apiKey",
  "authDomain": "projectId.firebaseapp.com",
  "databaseURL": "https://databaseName.firebaseio.com",
  "storageBucket": "projectId.appspot.com"
}

Python × Firebase 認証の実装

1. ライブラリのインストール

Pyrebase4 を導入します。

poetry add Pyrebase4

2. 認証ロジックの実装

Firebase 認証を行うロジックを firebase.py として保存します。認証されたユーザーは st.session_state に入れておく実装としてみましょう。

firebase.py
import json
import pyrebase
import requests
import streamlit as st
from config import firebase as cfg

firebase = pyrebase.initialize_app(cfg)
auth = firebase.auth()

def authenticate(email, password):
    try:
        user = auth.sign_in_with_email_and_password(email, password)
        st.session_state.user = user
        return True

    except requests.exceptions.HTTPError as e:
        msg = json.loads(e.args[1])["error"]["message"]
        if msg == "EMAIL_NOT_FOUND" or msg == "INVALID_PASSWORD":
            st.error("メールアドレスかパスワードに誤りがあります。")
        elif msg == "USER_DISABLED":
            st.error("このユーザーは無効化されています。管理者にお問い合わせください。")
        elif msg == "TOO_MANY_ATTEMPTS_TRY_LATER":
            st.error("試行回数が多すぎます。しばらく経ってからお試しください。")
        else:
            st.error("ログインに失敗しました。")

        if "user" in st.session_state:
            del st.session_state.user
    return False

def refresh():
    if "user" not in st.session_state:
        return False
    try:
        user = auth.refresh(st.session_state.user["refreshToken"])
        st.session_state.user = user
        return True
    except Exception:
        del st.session_state.user
    return False

3. 画面の制御を実装

  1. の関数を利用し、認証状態によって画面遷移する home.py に修正してみます。
home.py
import streamlit as st
import firebase

def login():
    email = st.empty()
    email = email.text_input("Email アドレスを入力してください")
    password = st.text_input("パスワードを入力してください", type="password")
    submit = st.button("ログイン")
    if submit and firebase.authenticate(email, password):
        st.experimental_rerun()

def index():
    if not firebase.refresh():
        st.experimental_rerun()
        return
    st.text("ログインしました")

if "user" not in st.session_state:
    login()
else:
    index()

静的解析をしつつ、スタイルもフォーマットします。

./test.sh

4. クラウドへのデプロイ

問題なければ、これを Cloud Run にデプロイしてみましょう!

gcloud run deploy my-app --region "asia-northeast1" --source .

Cloud Run のサービスにアクセスしてみると、以下のような画面に変わっていると思います。Firebase に登録したユーザーでログインしてみましょう。

「ログインしました」というメッセージが表示されましたか?されていれば、認証ロジック完成です 🎉🎉🎉

次は BigQuery へのクエリーとその可視化を実装してみます。

Google Cloud Japan

Discussion