【Python】FlaskでWebアプリケーションを作る⑦ -ログイン機能を実装する

今回はFlaskのWebアプリケーションにログイン機能を実装します。

前提

今回は最もシンプルな方法でログイン機能を実装します。SSO等は一切考慮していません。また、DBとの接続もせず、あくまでFlask内のログイン機能の実装にフォーカスを当てます。

フォルダ構成

フォルダ構成は以下の通りです。画面はログイン画面と、ログイン後の画面の2つです。

..
L templates
|   L dashbord.html
|   L login.html
L main.py

HTMLファイル

以下HTMLの中身です。

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    {% if error %}
    <p>{{ error }}</p>
    {% endif %}
    <form method="post" action="/login">
        <label>Username:</label>
        <input type="text" name="username" required>
        <br>
        <label>Password:</label>
        <input type="password" name="password" required>
        <br>
        <input type="submit" value="Login">
    </form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
    <title>Dashboard</title>
</head>
<body>
    <h1>Welcome, {{ session["username"] }}!</h1>
    <p>This is your dashboard.</p>
    <!-- ログアウトボタンを追加 -->
    <form action="/logout" method="post">
        <input type="submit" value="Logout">
    </form>
</body>
</html>

Flaskで実装

パッケージのインストール

今回必要なのは、Flaskの以下パッケージです。

from flask import Flask, render_template, request, redirect, url_for, session

ユーザ情報の定義

今回ログインできるユーザ情報はプログラムに辞書形式で定義します。一般的にアカウント情報はDB等で管理します。DBから取得する場合は、以下の部分をDBで取得するように変更してください。

# シンプルなユーザーデータの辞書
users = {
    'user1': {'username': 'user1', 'password': 'password1'},
    'user2': {'username': 'user2', 'password': 'password2'}
}

ログイン画面について

まず、http://127.0.0.1:5000/(ローカルの場合)にアクセスすると、login.htmlを表示するようにします。

@app.route("/")
def main_page():
    return render_template('login.html')

ログイン画面は以下のようなものです。

login.html

ログイン機能の実装

ログインはlogin()関数にて実装します。login()は、ログイン画面が”Login”ボタンを押すことで呼ばれます。

関数は以下内容とします。

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 画面で入力された情報を取得
        username = request.form['username']
        password = request.form['password']

        # ログイン可否を判定
        if username in users and users[username]['password'] == password:
            session['username'] = username

            # ログイン成功でdashbord.htmlを返す
            return redirect(url_for('dashboard'))
        else:
            return render_template('login.html', error='Invalid credentials')

  # GETの場合はログイン画面へ戻す
    return render_template('login.html')

GET、POSTどちらでも受け付けますが、処理の中でGETの場合はログイン画面に再び戻しています。なので、実質的にPOSTでログインすることになります。

login.htmlからは画面で入力したusernameとpasswordが渡されます。それらはrequest.formから取り出します。

受け取った情報が登録されている情報と一致する場合は、セッションにユーザ情報を格納し、dashbord.htmlを返します。

dashbord画面は以下のような画面です。

dashbord.html

直接dashbord.htmlにアクセスしようとした場合について

Login画面からはdashbord.htmlに繋がるかの制御を実施していますが、URLで直接http://127.0.0.1:5000/dashboardが実行された場合の制御もしておく必要があります。

具体的には、セッション情報に”username”が存在するかで判定します。これは、ログイン成功時にセッションに追加されるものです。

@app.route('/dashboard')
def dashboard():
    if 'username' in session:
        return render_template('dashbord.html')
    else:
        return redirect(url_for('login'))

なお、実際のセキュリティ要件に合わせてこういったケースでさらに厳密な制御が求められる場合もあります。今回はあくまで最低限のログイン機能なので、状況に応じて認証方法を変更してください。

ログアウト機能の実装

dashbord.htmlには、Logoutボタンがついています。ボタンを押すと、ログアウトできるようにします。

@app.route('/logout', methods=['GET', 'POST'])
def logout():
    session.pop('username', None)
    return redirect(url_for('login'))

ログアウト方法として、セッションからusernameを削除しています。

そして、ログイン画面に遷移します。

コード全体

最後にmain.pyのコード全体です。

from flask import Flask, render_template, request, redirect, url_for, session

app = Flask(__name__)

# シンプルなユーザーデータの辞書(適宜DB接続等実施してください)
users = {
    'user1': {'username': 'user1', 'password': 'password1'},
    'user2': {'username': 'user2', 'password': 'password2'}
}

@app.route("/")
def main_page():
    return render_template('login.html')

#ログイン処理
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 画面で入力された情報を取得
        username = request.form['username']
        password = request.form['password']

        # ログイン可否を判定
        if username in users and users[username]['password'] == password:
            session['username'] = username

            # ログイン成功でdashbord.htmlを返す
            return redirect(url_for('dashboard'))
        else:
            return render_template('login.html', error='Invalid credentials')

    # GETの場合はログイン画面へ戻す
    return render_template('login.html')

#URL直接参照の場合
@app.route('/dashboard')
def dashboard():
    # ログインしている場合はdashbord.htmlへ
    if 'username' in session:
        return render_template('dashbord.html')
    else:
        return redirect(url_for('login'))


#ログアウト機能
@app.route('/logout', methods=['GET', 'POST'])
def logout():
    session.pop('username', None)
    return redirect(url_for('login'))

if __name__ == "__main__":
    app.run()

まとめ

Flaskでログイン機能を実装する方法を紹介しました。アプリケーションによってセキュリティ要件は変わってくるので、必要に応じて認証方法等は変更してください。Flaskでの構成については、本記事が参考になれば幸いです。

ではでは👋