前回の記事の続きとなります。
flaskのチュートリアルでflaskrというシンプルなブログアプリを作成しています。
今回は、ログインのプログラムから実装を行っていきます。flaskの公式チュートリアルのページはこちらとなります。
こんな人の役に立つかも
・PythonのflaskでWebアプリケーションを作成したい人
・flaskの勉強をしている人
・flaskのblueprintを勉強している人
auth.pyへのプログラミング
「flaskr」フォルダ内の「auth.py」に、プログラムを追加していきます。
ログイン処理
ログイン処理として、次のviewのプログラムを追加します。
#「/auth/login」というURLのルーティングです
@bp.route('/login', methods=('GET', 'POST'))
def login():
#POSTメソッドのとき
if request.method == 'POST':
#①フォームの内容を読み込み、DB初期化します
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
#②データベースからユーザーの情報を取得します。
user = db.execute(
'SELECT * FROM user WHERE username = ?', (username,)
).fetchone()
#③ユーザー情報がない場合のエラー処理です。
if user is None:
error = 'Incorrect username.'
#④ユーザー情報が存在する場合、パスワードが正しいか確認
elif not check_password_hash(user['password'], password):
error = 'Incorrect password.'
#⑤セッションにユーザーID格納
#なんのエラーもない場合errorはNoneなので以下処理を行います。
if error is None:
#セッションにユーザーIDを記憶してindexへリダイレクト
session.clear()
session['user_id'] = user['id']
return redirect(url_for('index'))
flash(error)
return render_template('auth/login.html')
前回のregister処理と同様にして、POSTメソッドのときの動作とGETメソッドの動作を条件分岐します。
①フォームの内容を読み込み、DBを初期化
registerのときと同様に、フォームからPOSTされたusernameとpasswordを格納します。そして、get_dbでDBへ接続します。
②データベースからユーザーの情報を取得
registerのときと同じように、SQL文を実行してuserテーブルからユーザー情報を取り出します。
③エラー処理
②のSQL文で何も取得できなかったら、ユーザーが存在していませんので、エラーとします。errorにメッセージを記載します。
④パスワードが正しいか確認
②のSQL文でユーザーデータが取得できた時は、パスワードが正しいか照合を行います。「check_password_hash(DB取得のパスワード, 入力パスワード)」 でチェックします。データベースのパスワードはハッシュ化していますので、このようにして比較します。
⑤セッションにユーザーID格納
最後に、error変数がNoneのときは、正常にユーザー情報を取得できていますので、セッションにユーザーIDを書き込みます。
セッション、flashなど、クイックスタートでやった知識が詰め込まれています。
リクエスト前に毎回行う処理
引き続き、「auth.py」にプログラミングを行います。次のプログラムを追加します。
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
#gオブジェクトにユーザー情報を格納
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM user WHERE id = ?', (user_id,)
).fetchone()
「before_app_request」を指定すると、「URLが要求されてview関数が動作する前に」動作するプログラムを作成できます。セッションに既にユーザーIDが登録されているかどうかを確認する処理を行っています。
ユーザーIDが登録されている場合、データベースへ接続して、データベース情報からユーザー情報を「g」オブジェクトへ取得します。
ログイン処理で、セッションにユーザーIDを格納することで、ブラウザにログイン状態を保存できるので、すでにログインしているかどうか等の確認に利用することができそうです。
ログアウト処理
ログアウト処理です。セッションからユーザーIDを削除(セッション自体をクリア)することでログアウト処理になります。次のリクエストで「@bp.before_app_request 」が呼び出されても、セッションがNoneになるので、ログインしていない状態ということになります。
@bp.route('/logout')
def logout():
session.clear()
return redirect(url_for('index'))
ログインしているかを確認する処理(デコレータ)
デコレータというものを利用して、ログイン確認を行います。デコレータは、function.wrapsを利用して次のように定義することで、「@関数名」のようにして、処理を簡単に追加できるようになります。
#デコレータ
(次から@login_requiredで利用できる)
def login_required(view):
@functools.wraps(view)
#以下の内容がデコレータで追加される処理
def wrapped_view(**kwargs):
if g.user is None:
return redirect(url_for('auth.login'))
return view(**kwargs)
return wrapped_view
デコレータの処理は、「wrapped_view」という中で記述されています。gオブジェクトをみて、ユーザーIDがNoneのときはログインしていない、と判断し、ログイン画面にリダイレクトをかける、というものです。
この「デコレータ」という処理は、後のブログ投稿、削除など、ログインしていないとできない処理の前に「@login_required」とつけてあげることで毎回この処理を追加できる、というものになります。
処理例
いろいろ出てきましたので、処理の例で作成したviewプログラムの動作順を整理してみました。
リクエスト前に行われる「load_logged_in_user」で、セッションのユーザーIDが取り出されます。そして、「g」に格納されます。
デコレータ「login_required」の処理で、ユーザーがログインしているかどうかの判定を行います。
そして、投稿などの本処理を行います。
本日の振り返り
ちょっといろいろな技術要素がでてきて、ボリュームが多くなってしまいました^^;
ユーザーのログイン、ログアウトの処理の最重要点は、「セッションにユーザー名を登録してあるかどうかを判断する点」であることがわかりました。
リクエスト毎にセッションでユーザーIDをデータベースに照合することでログイン状態か、ログイン状態でないかを判定しています。
セッションについてはクイックチュートリアルで勉強していますので、次の記事をご参照ください。