【Streamlit v1.46.1】認証モジュール + SQLite3を使ってログイン機能を実装
ログイン/サインアップ機能を、streamlit-authenticator モジュールを使って行います。ユーザー情報はSQLite3に保存して永続化し、パスワードはハッシュ化しています。
streamlit-authenticator は、Streamlitアプリケーションにユーザー認証機能を追加するためのライブラリです。ログイン機能に必要な入力フォームの自動作成とセッションステータスの管理が簡単に行えます。
また、Streamlitはデフォルトで同期的に動作するフレームワークですので、SQLite3との連携も同期処理で行います。
目次
開発環境
- OS: Ubuntu22.04
- version:Streamlit v1.46.1 / streamlit-authenticate v0.4.2
- 仮想環境でのインストール
pip install streamlit==1.46.1
pip install streamlit-authenticate==0.4.2
SQLite3の準備
- DBスキーマの設計
- サンプル・ユーザー作成
(1)DBスキーマの設計
createdb.py(DBスキーマの設計)→これをpython3 createdb.pyで実行する。
import sqlite3
import logging
conn = sqlite3.connect("st-menber.db")
c = conn.cursor()
# usersテーブルの作成
try:
c.execute("drop table if exists users")
c.execute("""
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL
)
""")
except Exception as e:
logging.exception("エラーが発生しました: %s", e)
else :
print("データベースの作成に成功しました")
createdb.pyの実行結果(データベースの作成)
# 下記コマンドで実行させます。
python3 createdb.py
データベースの作成に成功しました
(2)サンプル・ユーザー作成
insertdb.py(ユーザー登録処理検証)→ python3 insertdb.pyで実行
import sqlite3
import logging
conn = sqlite3.connect("st-menber.db")
cursor = conn.cursor()
# ここではpassword平文のまま動作確認。
sample_user = [
("sanji", "pass123"),
("usop", "pass345")
]
try:
cursor.executemany("insert into users (username, password) values (?,?)",sample_user)
conn.commit() # ← コミットを忘れないでください。
conn.close() # ← 必ずクローズさせる。
except Exception as e:
logging.exception("エラーが発生しました: %s", e)
else:
print("サンプルユーザーの作成に成功しました")
insertdb.pyの実行結果(テーブルの作成と確認)
# (1) 下記コマンドで実行させます。
python3 insertdb.py
サンプルユーザーの作成に成功しました
# (2) sqlite3をコマンドラインで起動。
sqlite3 st-menber.db
SQLite version 3.37.2
Enter ".help" for usage hints.
# (3) テーブ内容表示
sqlite> select * from users;
1|sanji|pass123
2|usop|pass345
# (4) 抜ける
sqlite> .quit
以上で、StreamlitからSQLite3と接続できることが分かりました。次はStreamlitの認証機能とデータベースとを統合します。
streamlit-authenticatorとの統合
パスワードのハッシュ化してユーザー情報を登録
先程のinsertdb.pyを追加・修正します。パスワードのハッシュ化には、Streamlit_authenticatorのHasherクラスのhash()メソッドを使います。
insertdb.pyの修正
import sqlite3
import logging
import streamlit_authenticator as stauth # ← 追加
conn = sqlite3.connect("st-menber.db")
cursor = conn.cursor()
sample_user = [
("sanji", stauth.Hasher.hash("pass123")), # ← 修正
("usop", stauth.Hasher.hash("pass345")) # ← 修正
]
try:
cursor.executemany("insert into users (username, password) values (?,?)",sample_user)
conn.commit()
conn.close()
print("サンプルユーザーの作成に成功しました")
except Exception as e:
logging.exception("エラーが発生しました: %s", e)
streamlit-authenticatorの使い方
- データベースから既存のユーザー情報を取得し、Authenticate()メソッドで初期化する。
- 最新版ではユーザー情報は全て辞書形式でまとめる。
- ログインフォームの生成
①ユーザー情報は辞書形式でまとめる。
fetch_users()関数は、streamlit-authenticateのAuthenticate()メソッドに渡すcredentials変数を自動生成します。
def fetch_users(conn):
try:
cur = conn.cursor()
cur.execute("select username ,password from users")
rows = cur.fetchall()
credentials = {"usernames":{}}
# credentials = {}
for row in rows:
username, hashed_password = row
tmp_dict = {
'name': username, # ここでusernameをnameとして使用
'password': hashed_password,
}
credentials["usernames"][username] =tmp_dict
conn.close()
return credentials
except Exception as e:
st.error(f"ユーザー情報取得エラー: {e}")
return {"usernames": {}}
先程のinsertdb.pyで追加したユーザー情報を基に作成したcredentials辞書を、読み易いように展開すると以下のようになります。fetch_users()関数はこれを自動生成して返しています。
# sample
credentials = {
"usernames": {
"sanji": {
"name": "sanji",
"password": stauth.Hasher.hash('pass123')
},
"usop": {
"name": "usop",
"password": stauth.Hasher.hash('pass456')
}
}
}
②認証オブジェクトの作成(初期化)
認証オブジェクト名をauthenticatorとしています。
authenticator = stauth.Authenticate(
credentials=credentials, # ← ①でまとめたcredentialsを渡す
cookie_name="my_app_cookie", # 任意のクッキー名
cookie_key="super_secret_key", # 任意の署名キー(テストのため直書きで済ませています)
cookie_expiry_days=30 # クッキーの有効期限(日数)
)
③ログインフォームの生成
認証オブジェクトauthenticatorのlogin()メソッドを呼び出します。これだけでログインフォームが自動生成されます。
authenticator.login(
location="sidebar",
fields={
"Form name": "ログイン",
"Username": "ユーザー名",
"Password": "パスワード",
"Login": "ログイン"
}
streamlit-authenticate v0.4.2からの変更箇所まとめ
streamlit-authenticateは、2025年7月時点の最新版はv0.4.2です。旧バージョンから処理内容が大きく変わっていますので、ご注意ください。
主な変更一覧

アプリ実行
app.pyの全コード
"""
Streamlit + SQlite3 + streamlit_authenticator
によるログイン/サインアップ機能
"""
# v1.46.1
import streamlit as st
# ↓画像を扱いたい方は以下もimportすると便利です。
from PIL import Image
import sqlite3
import streamlit_authenticator as stauth # 追加
# 状態管理
if "page" not in st.session_state:
st.session_state["page"] = "login"
if "mypage" not in st.session_state:
st.session_state["mypage"] = "Home"
# 画面遷移先
def Home():
st.header('ホーム画面')
img1="./images/公園の河.jpg"
img2="./images/palazzina寺院.jpg"
col1,col2 = st.columns(2)
with col1:
image1= Image.open(img1)
st.image(image1)
with col2:
image2 = Image.open(img2)
st.image(image2)
def info():
st.header('お知らせ')
st.write("〇〇公園のひまわりが見頃です。")
st.write("〇〇町の祇園祭が無事終了しました。")
def inquiry():
st.header('お問い合わせ')
# credentials作成
def fetch_users(conn):
try:
cur = conn.cursor()
cur.execute("select username ,password from users")
rows = cur.fetchall()
credentials = {"usernames":{}}
for row in rows:
username, hashed_password = row
tmp_dict = {
'name': username, # ここでusernameをnameとして使用
'password': hashed_password,
}
credentials["usernames"][username] =tmp_dict
conn.close()
return credentials
except Exception as e:
st.error(f"ユーザー情報取得エラー: {e}")
return {"usernames": {}}
# -新規登録
def regist_user(conn, username, hashed_password):
conn = sqlite3.connect("st-menber.db") # 一旦conn.close()しているので再度接続する!
try:
cur = conn.cursor()
cur.execute("insert into users (username, password) values (?, ?)",(username, hashed_password))
conn.commit()
conn.close()
return True
except sqlite3.IntegrityError :
st.warning("このユーザー名は既に登録されています。別のユーザー名をお試しください。")
return False
except Exception as e:
st.error(f"ユーザー登録エラー: {e}")
return False
# --メイン関数--
def main():
conn = sqlite3.connect("st-menber.db")
if conn is None:
st.error("データベースへの接続に失敗しました。アプリケーションを終了します。")
st.stop() # データベース接続ができない場合はここで停止
mycredentials = fetch_users(conn)
# ↓ローカル環境なので直書き
mysignature_key = 'super_secret123456!#$_verylonglong-cool'
authenticator = stauth.Authenticate(
mycredentials,
'streamlit_v1.46_login_cookie', # 任意のクッキー名
mysignature_key, # 任意の署名キー
cookie_expiry_days=30, # クッキーの有効期限(日数)
)
# サイドバーの設計
with st.sidebar:
if st.session_state["page"]== "login":
if st.button("新規登録はこちらから"):
st.session_state["page"] = "signup"
st.rerun()
st.divider()
authenticator.login(location="sidebar",fields={
"Form name": "ログイン",
"Username": "ユーザー名",
"Password": "パスワード",
"Login": "ログイン"
})
if st.session_state["authentication_status"]:
st.session_state["page"] = "dashboard"
# print(st.session_state["authentication_status"])
elif st.session_state["authentication_status"] is False:
st.error("ユーザー名またはパスワードが間違っています")
elif st.session_state["authentication_status"] is None:
st.warning("ユーザー名とパスワードを入力してください")
elif st.session_state["page"]== "dashboard":
# st.markdown("ログインに成功しました。 \nようこそ!!") # OK ※半角スペース2個+\nで改行になる
if st.session_state["authentication_status"]:
st.write("ログインに成功しました。")
st.success(f"ようこそ {st.session_state['name']} さん!")
st.session_state["page"] = "dashboard"
dash_page = st.selectbox('選択してください',['Home','お知らせ', 'お問い合わせ'])
st.session_state["mypage"] = dash_page
authenticator.logout("ログアウト", location="sidebar")
if st.session_state["authentication_status"] is None:
st.session_state["page"] = "login"
st.warning("ログアウトしました。再度ログインしてください。")
st.rerun()
elif st.session_state["page"] == "signup":
st.header('登録フォーム')
st.write("アカウントをお持ちでない方はこちらから登録してください。")
with st.form("register_user_form"):
username = st.text_input("ユーザー名")
new_password = st.text_input("パスワード", type="password")
confirm_password = st.text_input("パスワードの確認", type="password")
submit_registration = st.form_submit_button("登録する")
if submit_registration:
if username and new_password and confirm_password:
if new_password == confirm_password :
try:
hashed_password = stauth.Hasher.hash(new_password)
if regist_user(conn, username, hashed_password):
st.session_state["page"] = "login"
st.markdown("<span style='color:blue;'>ご登録ありがとうございました。</span>", unsafe_allow_html=True)
st.rerun()
except Exception as e:
st.error(f"パスワードのハッシュ化または登録中にエラーが発生しました: {e}")
else:
st.error("パスワードが一致しません。再度確認してください。")
else :
st.error("全ての登録項目を入力してください。")
st.divider()
if st.button("ログイン画面に戻る"):
st.session_state["page"] = "login"
st.rerun()
# メイン画面の設計
if st.session_state["page"] == "dashboard":
# 画面遷移
if st.session_state["mypage"] == "Home":
Home()
elif st.session_state["mypage"] == "お知らせ":
info()
elif st.session_state["mypage"] == "お問い合わせ":
inquiry()
if __name__ == '__main__':
main()
実行するには次のコマンドを入力してください。
streamlit run app.py
ローカル環境でのブラウザ動作
最終的なusersテーブル:パスワードはちゃんとハッシュ化されています。

以上です。😀