ラズパイデスクトップでFlask入門(7)Blueprint and Views(3)Login Logout

こんばんは。國松です。
 何だか今日はとても寒かったです。開発室の暖房の風量を1つ上げてしまいました。
今回はLoginとLogoutのViewを作成していきたいと思います。
参考サイト
 Welcome to Flask (英語版)
 Flaskへようこそ (日本語版)(このサイトのチュートリアルは上記英語版とは異なるので注意して下さい) 
Login
 LoginビューはRegisterビューと同じパターンに従います。Registerビューとの違いがいくつかあります。
 flaskr/auth.py(auth.pyに追記していきます)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24  | @bp.route('/login', methods=('GET', 'POST')) def login():     if request.method == 'POST':         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.'         if error is None:             session.clear()             session['user_id'] = user['id']             return redirect(url_for('index'))         flash(error)     return render_template('auth/login.html')  | 
1.ユーザーは最後に照会され後で使用するために変数に保存されます。
 2.check_pasword_hash()は保存されたハッシュと同じ方法でハッシュし、それらを安全に比較します。それらが一致する場合パスワードは有効です。
 3.sessionは一度ログインしたらどのページでもログイン状態を維持する仕組みです。FlaskではCookieを用いて実装されています。Cookieにログインしたという記録を保存し、それを読み出すことでログインしたかどうかの状態を判定します。
以上でユーザーのIDがsessionに保存されたので以降のリクエストが利用できるようになります。各リクエスト開始時に、ユーザーがログインしている場合、情報をロードして他のビューで利用できる様にする必要があります。
flaslr/auth.py(auth.pyに追記していきます)
1 2 3 4 5 6 7 8 9 10  | @bp.before_app_request def load_logged_in_user():     user_id = session.get('user_id')     if user_id is None:         g.user = None     else:         g.user = get_db().execute(             'SELECT * FROM user WHERE id = ?', (user_id,)         ).fetchone()  | 
bp.before_request()は要求されたURLに関係なくview関数の前に実行される関数を登録します。
 load_logged_in_uerはユーザーIDがsessionに保存されているかを確認し、そのユーザーのデータをデータベースから取得してそれを要求の期間中g.uerに保存します。
 ユーザーIDがない場合、またはIDが存在しない場合、g.userはNoneになります。
Logout
 ログアウトするにはsessionからユーザーIDを削除する必要があります。
 その後、load_logged_in_userは後続のリクエストでユーザーをロードしません。
 flaslr/auth.py(auth.pyに追記していきます)
 
1 2 3 4  | @bp.route('/logout') def logout():     session.clear()     return redirect(url_for('index'))  | 
Require Authentication in Other Views
 ブログの投稿を作成、編集、削除するにはユーザーがログインする必要があります。
 デコレーターを使用して適用される各ビューをこれで確認できます。
 デコレーターとは既存の関数の処理の前後に新しく処理を付け加える事が出来るしくみです。詳しくは以下のサイトなどを参考にしてください。
 Pythonのデコレーターについて
 flaslr/auth.py(auth.pyに追記していきます)
1 2 3 4 5 6 7 8 9  | 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  | 
このデコレータはそれが適用されている元のビューをラップする新しいビュー関数を返します。新しい関数はユーザーがロードされているかを確認しロードされていない場合はログインページにリダイレクトします。
 ユーザーがロードされると元のビューが呼び出され通常通りに続行されます。
 Blogビューを作成するときにこのデコレータを使用します。
Endpoints and URLs
 url_for()関数は名前と引数に基づいてビューへのURLを生成します。ビューに関連付けらている名前はエンドポイントともよばれ、デフォルトではビュー関数と同じ名前です。
 例えばhello()ビューの名前は「hello」でありurl_for(Hello)dでリンクできます。
 Blueprintを使用する場合Blueprintの名前は関数の名前の前に追加されるためLogin()関数のエンドポイントは「auth.login」になります。
次回はTemplateを作成していきたいと思います。

