Squadbase
Apr 22
Streamlitでユーザー認証を実現する方法3選
三橋 啓多
Co-founder, COO

Streamlitは、Pythonで本格的なWebアプリを開発することができ、主に社内向けのAIアプリやデータアプリの構築のために広く採用されています。Streamlitで構築したアプリを本格的に運用するためには、ユーザー認証の実装が必要になります。本記事では、Streamlitアプリにユーザー認証を実装するための主な手段を比較します。ユースケースとしては、社内向けアプリにおけるユーザー認証の実現を想定します。

Open ID Connect (OIDC)

Open ID Connect (OIDC) は、Streamlitが公式に提供しているユーザー認証の方法です。オープンプロトコルであり、様々なアイデンティティプロバイダー (IDプロバイダー) で採用されている仕様であるOIDCを用いてユーザーを認証します。Streamlit v1.32以上で利用可能です。

StreamlitアプリにOIDCによるユーザー認証を実装するためには、ユーザーを認証するサーバーであるIDプロバイダーを利用する必要があります。公式ドキュメントでは、Auth0やGoogle Identityなどが紹介されていますが、OIDCに対応したIDプロバイダーであれば何でも利用することができます。

裏を返せば、外部のIDプロバイダーを必ず利用する必要があるため、既に社内アプリ向けに整備されたIDプロバイダーを運用していればそれを使うことができますが、未整備の場合は新たに選定・構築する必要があります。

実装方法

Streamlitアプリのコード

import streamlit as st

if not st.experimental_user.is_logged_in:
    st.login("oidc")
    st.stop()

user = st.experimental_user
st.sidebar.markdown(f"**👋 Hello {user.email}!**")
st.button("ログアウト", on_click=st.logout)

.envでIDプロバイダーの情報を設定する

公式ドキュメントでは、 .streamlit/secrets.toml ファイルにIDプロバイダーの情報を記述する方法が紹介されていますが、.streamlit/secrets.toml ファイルを適切にハンドリングするには、Streamlit Communityクラウドを使うか、とても複雑なデプロイメントワークフローを構築する必要があります。そのため、ここではより多くの状況で利用可能な環境変数による設定方法を紹介します。以下では、IDプロバイダーとしてAuth0を利用する場合を紹介します。

.envファイルにAuth0の情報を設定する:

REDIRECT_URI=http://localhost:8501/oauth2callback
COOKIE_SECRET=<Random string>
CLIENT_ID=<Your Auth0 client ID>
CLIENT_SECRET=<Your Auth0 client secret>
AUTH0_METADATA_URL=https://{Your Auth0 tenant subdomain}.auth0.com/.well-known/openid-configuration

Streamlitコードからの利用:

import streamlit as st
import os
from dotenv import load_dotenv

def load_auth_config():
    load_dotenv() # load enviornment variables from .env file
    from streamlit.runtime.secrets import secrets_singleton

    # Set ID provider config as dict
    auth_secrets = {
        "auth": {
            "redirect_uri": f"{os.getenv('REDIRECT_URI')}",
            "cookie_secret": os.getenv('COOKIE_SECRET'),
            "auth0": {
                "client_id": os.getenv('CLIENT_ID'),
                "client_secret": os.getenv('CLIENT_SECRET'),
                "server_metadata_url": os.getenv('AUTH0_METADATA_URL'),
                "client_kwargs": {
                    "prompt": "login"
                }
            }
        }
    }

    secrets_singleton._secrets = auth_secrets

    for k, v in auth_secrets.items():
        secrets_singleton._maybe_set_environment_variable(k, v)

load_auth_config()

if not st.experimental_user.is_logged_in:
    st.login("oidc")
    st.stop()

user = st.experimental_user
st.sidebar.markdown(f"**👋 Hello {user.email}!**")
st.button("Logout", on_click=st.logout)

課題

IDプロバイダーを構成する必要がある

先述の通り、IDプロバイダーを別途選定・構成する必要があります。既に社内アプリ向けに整備されたIDプロバイダーを運用していればそれを使えばいいですが、そうでない場合はゼロから構築する必要があります。

認証方式やアクセスコントロールの管理はIDプロバイダー側の仕様に依存する

アプリケーションコード中でユーザーのロール情報などのメタデータを付与したい場合、それが可能かどうかはIDプロバイダーの仕様に依存します。

たとえばAuth0の場合は、Auth0のプラットフォーム上でグローバルなユーザーロールを設定することができますが、ロールの取得にはAuth0のAPIをコールする必要があります。

また、シングルサインオンやSAMLを認証に使用できるかどうかも、IDプロバイダーの仕様に依存します。

複数アプリで異なるアクセス制限を運用したい場合には、その数だけIDプロバイダーを構成する必要がある

仮にロール管理に対応しているIDプロバイダーを選定したとしても、複数アプリの運用下で、ユーザーのロールをアプリによって切り替えたい場合は運用が複雑になります。基本的にはIDプロバイダー上でアプリごとのユーザープールを構成する必要があり、その分コストがかかってしまいます。

Streamlit Authenticator

Streamlit AuthenticatorはStreamlit向けのコミュニティパッケージであり、ユーザー認証を簡単に追加できることで人気で、外部のIDプロバイダーを利用する必要がありません。

認証情報は事前にymlファイルとして構成します。ymlファイルにはユーザーのメタデータを追加することができ、これを用いてロール管理などが実現できます。

実装方法

cookie:
  expiry_days: 30
  key: # To be filled with any string
  name: # To be filled with any string
credentials:
  usernames:
    jsmith:
      email: jsmith@gmail.com
      failed_login_attempts: 0 # Will be managed automatically
      first_name: John
      last_name: Smith
      logged_in: False # Will be managed automatically
      password: abc # Will be hashed automatically
      roles: # Optional
      - admin
      - editor
      - viewer
import streamlit as st
import streamlit_authenticator as stauth
from dotenv import load_dotenv
from yaml import safe_load

with open("config.yaml") as f:
    config = safe_load(f)

load_dotenv()
authenticator = stauth.Authenticate(
    credentials=config["credentials"],
    cookie_name="my_app",
    cookie_key=os.getenv('COOKIE_SECRET_KEY'),
    cookie_expiry_days=7,
)

name, auth_status, username = authenticator.login("Login", "main")
if auth_status is False:
    st.error("ユーザー名かパスワードが違います")
elif auth_status is None:
    st.warning("ユーザー名とパスワードを入力してください")
else:
    st.sidebar.success(f"ようこそ {name}")
    # ビジネスロジック
    if st.sidebar.button("ログアウト"):
        authenticator.logout("ログアウト", "sidebar")

課題

SSOやSAMLには非対応

Googleなどのソーシャルアカウントを用いたシングルサインオンや、SAMLによるエンタープライズログインには対応していません。

本格的な運用には多くの追加実装が必要

本格的にアプリを運用していくと、ユーザー認証とは単なるログイン/ログアウトだけではないということに気づきます。たとえば、パスワードを忘れた場合やユーザー名を忘れた場合のワークフローや、ユーザープロフィールの変更などを実現するには多くの追加実装が必要です。

設定ファイルの変更のたびに再デプロイをする必要がある

ユーザー管理をYAMLファイルで行うため、ユーザー情報に変更があった場合にはYAMLファイルを更新する必要があります。YAMLファイルを外部のサーバーにホストすることも可能かもしれませんが、通常はアプリケーションコードベースに含まれていると思います。そのようなケースでは、ユーザー情報に変更があるたびにデプロイを再実行することになります。

また、ユーザー数が多くなると管理は難しくなります。

Squadbase

Squadbaseは組織向けのユーザー認証を備えたWebアプリのデリバリープラットフォームです。もちろん、Streamlitもデプロイすることができます。Streamlitの他にも、Next.jsやOllamaなどAIアプリ向けのフレームワークに対応しています。

組織内向けアプリのセキュアなデリバリーのために、以下のような機能を備えています。

組み込みのユーザー認証

Squadbaseにデプロイされたアプリは、Squadbaseのダッシュボードから招待したチームメンバーだけがアクセスが可能です。これはプラットフォームに組み込まれた機能であるため、一行のコードも追加する必要がありません。Squadbaseのユーザー認証はSSOに対応しています。

Githubリポジトリと連携するだけで継続的デプロイメントが構築され、デプロイ環境はセキュリティで保護されます。VercelやNetlifyのようなデリバリープラットフォームですが、組織向けアプリのために設計され、必要な機能が組み込まれています。

ロール付与

Squadbaseではユーザーにロールを付与することができます。プラットフォームへのデプロイやチームの管理をするためのチームロールと、デプロイされたプロジェクトごとに設定できるプロジェクトロールがあります。アプリケーションのコードから、アクセスしているユーザーの情報を参照するには、SDKを利用することができます。

undefined

プロジェクトロールはデプロイしたアプリごとに設定できるため、一つのプラットフォームで複数のアプリの権限管理を実現できます。

ログモニタリングとユーザーアナリティクス

Squadbaseでは、ランタイムのログやユーザーのアクセスログを自動で収集し、可視化します。ユーザーのアクセスログは集計され、アナリティクスとしてダッシュボードから閲覧することができます。それにより、組織向けアプリケーションの運用と改善に活用することができます。

(アナリティクスのスクショ)

(CTA)

まとめ (Final Thoughts)

最後に、ユースケースやシチュエーションごとの選定について考えていきます。

既に運用しているIDプロバイダーを使う必要があり、ロール管理が必要ない

既に社内アプリ向けのIDプロバイダーを運用しており、そのIDプロバイダーを引き続き利用する必要がある場合はStreamlit公式のOIDCが最適でしょう。既存のIDプロバイダーの設定情報を使ってユーザー認証が実現できます。

ただし、ロール管理が必要な場合や、複数アプリの運用をしたい場合には労力が伴う点は注意が必要です。

新たにユーザー認証を追加したい / ロールベースのアクセスコントロールを実現したい

手前味噌ですが、このような場合にはSquadbaseをおすすめします。あなたのStreamlitコードに変更を加えることなくユーザー認証が実現でき、ロールによるビジネスロジックの分岐をしたい場合にもSDKによって簡単に実装することができます。

Squadbaseにデプロイすれば、これらに加えてログの収集とモニタリングや、ユーザーの利用分析などがおまけでついてくる点もおすすめしたい理由の一つです。

とにかくユーザー認証ができればよく、本格的な運用はまだ考えていない

このような場合にはStreamlit Authenticatorが選択肢に入るかもしれません。外部のIDプロバイダーを構成する必要がなく、手元のコードだけでユーザー認証が実現できます。

ただし、ある程度の規模の運用を目指すのであれば、さまざまなユーザー管理フローの実装が必要になったり、大規模なユーザーベースをYAMLで管理し続けることがあまり現実的でないという点は留意すべきです。

Streamlit Authenticatorの場合でもある程度の実装は必要になるので、このケースでもSquadbaseをおすすめしたいです!