【Flask】セッション管理を使ってログイン機能を実装する

この記事では、Flaskのセッションについて紹介します。

Flaskではwebアプリとユーザを紐づけるためにセッションと呼ばれる技術を使います。

セッションを使うことで、ユーザ(クライアント)を識別することができます。

クライアントを識別することで、Amazonなどのサイトでカートにアイテムを保存しておくことも可能になります。

セッション管理を使ってログイン、ログアウト機能を持つ認証ページを作ってみたいと思います。

[toc]

作ってみるサイト

作成するページは以下の通り。

  • ログインページ

フォームを使ってIDとパスワードを入力させます。

  • Indexページ(ログイン後に遷移するページ)

ログインが成功したユーザ名を表示します。

仕様としては以下の通り。

  • セッションに保存するのは、ユーザIDとログイン状態(True,False)
  • indexページで、ログイン状態を確認しログイン済みであればユーザIDを表示する
  • 登録されていないユーザであればパスワードと共にセッションに保存しindexページへ移動(ユーザ登録(Sign Up)の役割をログインページでやってしまう)
  • ユーザIDとパスワードの組み合わせは辞書で管理する
  • ユーザIDに対するパスワードが違えば、パスワードが間違っているメッセージを表示する
  • ログアウトページで、セッションの値を全て削除

実装のポイントは、IDとPWはPOSTされてきたの時の処理ですね。

少し処理が長くなりますが、以下のような判定をするコードを書いていきます。

  1. 辞書内にIDがある場合
    1. PWの値を照合
      1. PWが合っていればログイン済みにする
      2. PWの値が合っていなければログイン済みにしない
  2. 辞書内にIDが無い場合
    1. IDとPWを新たに登録
    2. ログイン済みにする
  3. セッションにIDを保存
  4. ログイン済みであれば、indexページにリダイレクト
  5. ログイン済みで無ければ、PWが違うメッセージを表示する

ということで、以上を実装すると以下のコードになります。

コード

app.py

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

app = Flask(__name__)

app.secret_key = "aaa"

user_data = {}


@app.route("/", methods=["GET"])
def index():
    if "flag" in session and session["flag"]:
        msg = "hello,"+str(session["uid"])
        return render_template("index.html",
                               title="ログイン後の画面です",
                               message=msg)
    else:
        return redirect("/login")


@app.route('/login', methods=['GET'])
def login():
    return render_template("login.html",
                           title="ログインページ",
                           message="以下のフォームからログインしてね")


@app.route('/login', methods=['POST'])
def login_post():
    uid = request.form["uid"]
    pwd = request.form["pwd"]

    #ユーザが登録済みであった場合
    if uid in user_data:
        # IDとパスワードの組み合わせが合っていれば、ログイン済みにする
        if user_data[uid] == pwd:
            session["flag"] = True
        # ログイン済みにしない
        else:
            session["flag"] = False
    #ユーザが登録していなかった場合、登録してログイン済みにする
    else:
        user_data[uid] = pwd
        session["flag"] = True

    session["uid"] = uid

    if session["flag"]:
        return redirect("/")
    else:
        return render_template("login.html",
                               title="ログインページ",
                               message="パスワードが違います")


@app.route('/logout')
def logout():
    session.pop('uid', None)
    session.pop("flag", None)
    return redirect("/")

コードの簡単な解説

セッション情報の暗号化

セッションの情報は盗まれるとなりすましができてしまうため、秘密鍵を使って暗号化しています。`app.secret_key`というやつ。この値は何にしてもコードは動くが、もちろんバレないような乱数値の方が良い。

セッション情報の削除

session.popでは、セッションに保存された値を削除する。第二引数には、すでになかった場合に返す値を指定するがNoneを指定しておけば間違いない。

ログイン判定

indexページで、ログイン判定はどのようにやっているのでしょうか。

以下の2つの条件の確認を行っています。

  1. sessionにflagという名前のキーが存在するか
  2. flagがTrueであるか

2の条件で良いような気もしますが、なぜ1をチェックするのでしょうか。

セッション管理をする変数sessionはPythonの辞書と同じ性質を持ちます。

辞書ではキーが存在しないとエラーが発生します。辞書のキーが常に存在すれば必要ありませんが、今回の場合はログアウト機能のなかでキーの削除を行っています。

このような作りの場合には、辞書の値(value)の確認の前に、そもそもキーが存在するかどうかの確認も必要になってくるわけです。

参考

https://qiita.com/ikaro1192/items/d890eefbdbbfe1460252

 

ABOUTこの記事をかいた人

個人アプリ開発者。Python、Swift、Unityのことを発信します。月間2.5万PVブログ運営。 Twitter:@yamagablog