サイトアイコン アマチュア無線局JS2IIU

Dash応用編:第5回 Dashでのユーザー認証とセッション管理

こんにちは、JS2IIUです。今回はより実践的な「ユーザー認証」についてみていきます。よろしくお願いします。

はじめに

Dashアプリにログイン機能を追加し、ユーザー認証とセッション管理を行うことで、アプリケーションを安全かつユーザーごとにカスタマイズすることができます。このセクションでは、Flaskを利用してユーザー認証を実装し、セッション管理を使ってログイン状態を保持する方法を紹介します。

Flaskを利用したユーザー認証の実装

1. FlaskとDashの連携

DashはFlaskをベースに構築されているため、Flaskの機能を直接利用できます。まずは、Flaskのセッション機能を用いて簡単なユーザー認証システムを実装しましょう。出来上がりのイメージはこちらの画像の通りです。

https://js2iiu.com/wp-content/uploads/2024/10/da_05_01.mov

必要なライブラリのインストール

pip install dash flask

2. 簡単なユーザー認証フローの実装

以下のコードは、ユーザーがログインフォームを通じて認証し、セッションを利用して認証状態を保持するDashアプリの例です。

import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
import flask

# Flaskのサーバーインスタンス
server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server, external_stylesheets=[dbc.themes.BOOTSTRAP])

# シークレットキーの設定(セッション管理用)
server.secret_key = 'mysecret'

# レイアウト
app.layout = dbc.Container([
    dbc.Row([
        dbc.Col(html.H2("ログインフォーム"), width={"size": 6, "offset": 3}),
    ]),
    dbc.Row([
        dbc.Col(
            dbc.Form([
                # FormGroupは廃止されたため、直接Formを使用
                dbc.Row([
                    dbc.Col(dbc.Label("ユーザー名", html_for="username"), width=3),
                    dbc.Col(dbc.Input(type="text", id="username", placeholder="ユーザー名を入力"), width=9)
                ], className="mb-3"),  # 余白を追加

                dbc.Row([
                    dbc.Col(dbc.Label("パスワード", html_for="password"), width=3),
                    dbc.Col(dbc.Input(type="password", id="password", placeholder="パスワードを入力"), width=9)
                ], className="mb-3"),  # 余白を追加

                dbc.Button("ログイン", id="login-button", color="primary", className="mt-3"),
            ]),
            width={"size": 6, "offset": 3}
        )
    ]),
    html.Div(id="output-state"),
])

# コールバック
@app.callback(
    Output("output-state", "children"),
    [Input("login-button", "n_clicks")],
    [State("username", "value"), State("password", "value")]
)
def update_output(n_clicks, username, password):
    if n_clicks is None:
        return ""
    if username == "admin" and password == "password123":
        return "ログイン成功"
    else:
        return "ユーザー名またはパスワードが間違っています"

# アプリケーションの実行
if __name__ == '__main__':
    app.run_server(debug=True)

3. コードの解説

4. セッションの有効期限設定

セッションの有効期限を設定することも可能です。例えば、以下のようにFlaskのPERMANENT_SESSION_LIFETIMEを利用してセッションの有効期限を1時間に設定できます。

from datetime import timedelta

server.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1)

これにより、1時間経過後は自動的にログアウトされます。

5. セキュリティ対策

ユーザー認証とセッション管理において、以下のセキュリティ対策を考慮する必要があります。

このように、Flaskのセッション管理機能を活用することで、Dashアプリケーションにユーザー認証機能を簡単に組み込むことができます。

パスワードをハッシュ化するサンプル

ユーザー名とパスワードのハッシュ化を行うためには、Pythonのhashlibbcryptといったライブラリを使用するのが一般的です。ここでは、より安全なハッシュ化のために、bcryptを使用します。

実際に実装する場合は、ユーザー名とパスワードはデータベース等に保管するようにして下さい。このサンプルでは便宜的に直打ちしています。

bcrypt のインストール

まず、bcryptライブラリをインストールします。

pip install bcrypt
修正プログラム:

次に、パスワードをハッシュ化して保存し、ログイン時にハッシュ化されたパスワードと照合するプログラムに修正します。

import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
import flask
import bcrypt

# Flaskのサーバーインスタンス
server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server, external_stylesheets=[dbc.themes.BOOTSTRAP])

# シークレットキーの設定(セッション管理用)
server.secret_key = 'mysecret'

# ユーザー名とハッシュ化されたパスワードを保存する辞書
# 実際にはデータベースに保存することが推奨されます
users = {
    "admin": bcrypt.hashpw("password123".encode('utf-8'), bcrypt.gensalt())
}

# レイアウト
app.layout = dbc.Container([
    dbc.Row([
        dbc.Col(html.H2("ログインフォーム"), width={"size": 6, "offset": 3}),
    ]),
    dbc.Row([
        dbc.Col(
            dbc.Form([
                dbc.Row([
                    dbc.Col(dbc.Label("ユーザー名", html_for="username"), width=3),
                    dbc.Col(dbc.Input(type="text", id="username", placeholder="ユーザー名を入力"), width=9)
                ], className="mb-3"),

                dbc.Row([
                    dbc.Col(dbc.Label("パスワード", html_for="password"), width=3),
                    dbc.Col(dbc.Input(type="password", id="password", placeholder="パスワードを入力"), width=9)
                ], className="mb-3"),

                dbc.Button("ログイン", id="login-button", color="primary", className="mt-3"),
            ]),
            width={"size": 6, "offset": 3}
        )
    ]),
    html.Div(id="output-state"),
])

# コールバック
@app.callback(
    Output("output-state", "children"),
    [Input("login-button", "n_clicks")],
    [State("username", "value"), State("password", "value")]
)
def update_output(n_clicks, username, password):
    if n_clicks is None:
        return ""

    if username in users:
        # 入力されたパスワードをハッシュと照合
        if bcrypt.checkpw(password.encode('utf-8'), users[username]):
            return "ログイン成功"
        else:
            return "パスワードが間違っています"
    else:
        return "ユーザー名が間違っています"

# アプリケーションの実行
if __name__ == '__main__':
    app.run_server(debug=True)
変更点:
  1. bcryptによるハッシュ化: ユーザー登録時にパスワードをハッシュ化して保存し、ログイン時にハッシュを使って照合するように変更しました。
  2. users辞書: ユーザー名とハッシュ化されたパスワードを保持する辞書を作成。ここでは、例として"admin"ユーザーのパスワードを"password123"に設定し、それをハッシュ化しています。
  3. bcrypt.checkpwによる照合: ログイン時に入力されたパスワードが、ハッシュ化されたパスワードと一致するかを確認します。

この方法により、パスワードが安全に保存され、ハッシュ化されたパスワードを用いた認証が可能になります。

最後まで読んでいただきありがとうございます。73

Dash関連記事まとめ

DashはJavaScriptライブラリであるReactの上に構築されたPythonフレームワークであるが、DashはRでも動作し、最近ではJuliaもサポートしている。
Wikipedia – Plotly/Dash から引用、翻訳

モバイルバージョンを終了