コンテンツにスキップ

第9章 セッション

1 セッションとは

GETやPOSTで渡されたデータや、そのページに対応した関数内で生成したデータはそのページ内だけで消滅してしまい、他のページにアクセスしたときにそれらを参照することは出来ません。

しかし、ページ間でデータの受け渡しが出来ないと困る場合があります。例えばショッピングカートなどは他のページで購入した商品のデータをずっと保持しています。また、ログイン処理ではログインに成功した場合、「ログインした」という情報を他のページに受け渡さないといけません。

これらを実現するのがセッションです。Flaskのセッションではデータをブラウザに保存することでデータをページ間で受け渡すことを可能にします。

2 セッションの利用

セッションを利用するにはまずインポートを行います。なお、セッション利用時に便利に使えるflash関数もインポートしておきます。

from flask import session, flash

そして、Flaskオブジェクトを生成した後にシークレットキーを設定します。

app = Flask(__name__)
app.secret_key = b'\x83\xc9L:\xdf\x8a\x97\xb9\xef\xc4}G\t\xed\x1b('

このキーはブラウザにデータを保存する際の暗号化に使うキーです。これにより、ブラウザ側での改竄を防ぐことができます。推測されない値にする必要がありますので、上の例をそのまま使うことは出来ません。

自分独自のキーを生成するにはコマンドラインから以下のようにして生成するとランダムな文字列のキーが生成されます。

python -c "import os; print(os.urandom(16))"

シークレットキーを設定したら、sessionという名前の辞書を使うことができるようになります。例えば、ログインしたらユーザ名(uname)を保存する、という場合、以下のようにします。

session['uname'] = uname

なお、セッションを削除するには通常の辞書同様にpopを使います。

session.pop('uname')

3 ログイン

セッションを利用し、ログイン処理を作ってみましょう。まず、ログイン画面を表示します。

@app.get('/login')
def login():
    return render_template('login.html')

login.html は以下のようにします。ユーザ名をuname、パスワードをupassという名前で渡します。

<form action="/login" method="post" >
    ユーザ名:<input type="text" name="uname"><br>
    パスワード:<input type="password" name="upass"><br>
    <input type="submit" value="ログイン">
</form>

ユーザがログインボタンを押すと、/login にpostします。 /loginのpostでは、unameとupass を受け取り正しいパスワードかを判定します。以下の例では パスワードが abc ならログイン成功と見なしています。ログイン成功の場合、、セッションにunameを保存し、売上リスト(/ulist)にリダイレクトで移動します。

パスワードが異なる場合、ログイン画面に戻ります。

@app.post('/login')
def login_post():
    uname = request.form['uname']
    upass = request.form['upass']
    if upass == "abc":
        session['uname'] = uname
        return redirect("/ulist")
    else:
        return redirect("/login")

ログイン成功時にセッションに保存したidを ulist.html で表示してみます。 これは {{session.キー名}} で表示できます。

<p>ようこそ、{{session.uname}}さん</p>

4 フラッシュメッセージの利用

現状ではログインに失敗した場合、エラーメッセージが表示されません。これを表示するためにフラッシュメッセージを利用します。これはセッションの仕組みを利用するもので、指定したメッセージを1度だけ表示することが出来ます。

ログイン処理でパスワードを間違ったとき、リダイレクトする直前で、flashという関数でメッセージを指定します。

@app.post('/login')
def login_post():
    uname = request.form['uname']
    upass = request.form['upass']
    if upass == "abc":
        session['uname'] = uname
        return redirect("/ulist")
    else:
        flash("パスワードが違います")
        return redirect("/login")

flash関数で指定したメッセージをhtml側で以下のようにして表示します。

{% for message in get_flashed_messages() %}
    <p>{{ message }}</p>
{% endfor %}

フラッシュメッセージはリダイレクトした直後にしか表示されません。再読込したらメッセージは消えます。

5 ログアウト

セッション情報を削除するログアウト処理は辞書sessionからのキー削除で可能です。 例えば、/logout でログアウトし、/login にリダイレクトします。

@app.get('/logout')
def logout():
    session.pop('uname')
    return redirect("/login")

6 セッションの判定

ログインしているときにのみメッセージを出したい場合には、通常の辞書と同じく、"キー名" in session で調べられます。

{% if "uname" in session %}
    <p>ようこそ、{{session.uname}}さん</p>
{% endif %}

ログインしていないときの処理は、通常の辞書と同じく、"キー名" not in session で調べられます。ログインしていないときにulistにアクセスした場合、/loginにリダイレクトするようにしてみます。

@app.get('/ulist')
def ulist():
    # ログインの確認
    if "uname" not in session:
        return redirect("/login")

    rows = uriage.all()
    srows = shouhin.all()
    return render_template('ulist.html', rows=rows, srows=srows)