ブループリント??よくわからない言葉が出てきました。
プログラムを分割できるような機能みたいだね。
flaskチュートリアルの「Brueprints and Views」を進めていきます。今回は、Webアプリを開発していくうえで、プログラムの機能毎に分けて作成していくブループリントという機能を利用してオーソライズ関連の機能を実装していく内容となっています。
こんな人の役に立つかも
・flaskのチュートリアルをやっている人
・flaskでWebアプリを作成したい人
Blueprintについて
Blueprintという方法でアプリケーションのviewのプログラムを機能に関連するかたまりで分けて記述できるようです。
まずは、オーソライズ(ユーザーの登録、ログイン、ログアウト)関連の処理を「auth.py」というプログラムにまとめて記述していきます。
auth.pyを作成
今までのチュートリアルでは、「application.py」(または「__init__.py」のcreate_app内)に「@app.route()」とルーティングするプログラムをすべて直接記述していました。
今回から、viewの機能を担うプログラムが2つになります。
・__init__.py:アプリケーションファクトリでアプリを初期化したりします。
・auth.py:今回の記事で作成していきます。オーソライズ関連の機能をまとめたプログラムです。
まずは、次のように「flaskr」フォルダの中に「auth.py」を作成します。
#いろいろとimport
import functools
from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash
#db.pyに定義した「get_db」関数をimport
from flaskr.db import get_db
bp = Blueprint('auth', __name__, url_prefix='/auth')
Blurprintという関数で「auth」という名前のブループリントを作成するらしいです。url_prefixの引数では、このブループリントで作成するプログラムの前に「/auth」がつくように設定されています。そして、「bp」という名前のブループリントを作成しているのがわかります。
この「bp」というブループリントをアプリケーションに紐づけるために「__init__.py」に変更を加えます。
def create_app():
app = ...
#…略…
#Pythonパッケージのimportと同様にauth.pyを追加できます。
from . import auth
#先ほど作成したbpをこのようにappに紐づけます。
app.register_blueprint(auth.bp)
return app
「__init__.py」のアプリケーションファクトリ内に、「resister_blueprint」メソッドでブループリント「bp」を紐づけます。これで、URL「/auth」に関するプログラムを「auth.py」に記述できるようになりました。
ユーザー登録のプログラム
まずは、ユーザー登録のプログラムを作成していきます。
処理内容としては、フォーム「username」に入力されたユーザー名が既に登録されているものかを確認して、未登録のユーザー名の場合、パスワードとセットでデータベースに新規追加する、というものです。
「auth.py」に次のプログラムを追加します。
#①ルーティング
@bp.route('/register', methods=('GET', 'POST'))
def register():
#②POSTの時の処理
if request.method == 'POST':
#③requestオブジェクトからフォームの内容を取得
username = request.form['username']
password = request.form['password']
#SQLiteデータベースへ接続
db = get_db()
error = None
#④フォームへ未入力の場合のエラー処理
if not username:
error = 'Username is required.'
elif not password:
error = 'Password is required.'
#⑤入力内容が存在している場合の処理
elif db.execute(
'SELECT id FROM user WHERE username = ?', (username,)
).fetchone() is not None:
error = 'User {} is already registered.'.format(username)
#⑥エラーがない場合
if error is None:
db.execute(
'INSERT INTO user (username, password) VALUES (?, ?)',
(username, generate_password_hash(password))
)
db.commit()
#⑦「auth.login」へリダイレクトします。
return redirect(url_for('auth.login'))
#⑧エラーを返します。
flash(error)
#⑨retuen(GET、エラー)
return render_template('auth/register.html')
①ルーティング
@bp.route(‘/register’)のように、bpにルーティングを行っていきます。この場合は、ブループリント「bp」のurl_prefixが設定されているので、アクセスするURLは「/auth/register」というURLになります。
②POSTの時の処理
「/auth/register」に初めてアクセスするときはGETメソッドでアクセスされるので、この条件は飛びます。一度「register.html」のユーザー名とパスワードフォームに値が入力されて送信ボタンでPOSTメソッドが呼ばれた場合、この処理に入ります。
③requestオブジェクトからフォームの内容を取得
チュートリアルでもやったことがあるrequestオブジェクトからのPOSTの値取得です。
そして、「db.py」に定義したデータベースへの接続メソッド「get_db」を利用してデータベースへ接続します。
④フォームへ未入力の場合のエラー処理
username、passwordの内容が未入力の場合、error変数にそれぞれエラーメッセージを入れます。
⑤入力内容が存在している場合の処理
username、passwordに値が存在している場合、まずはusernameがすでに存在しているかどうか、データベースで確認します。
「db」の「excute」メソッドでSQL文を利用してデータベースにアクセスできます。
「SELECT文」で、「username = ?」という条件(?に入力値usernameが入り比較)で「user」テーブルに「id」が存在している場合その行を取得します。そして、「fetchone」というメソッドで、返ってきた行の1行を取得することができるようです。行が返ってきているということは、ユーザーが「user」テーブルに存在しているということなので、NONEではなくなります。この条件で「is NONE」の場合、データベースから
また、usernameがユーザー入力のため、この入力値によってはセキュリティの脆弱性が発生するのですが、データベースライブラリで値をエスケープして、SQLインジェクション攻撃に対して脆弱ではなくなっているとのことです。
⑥エラーがない場合
今までの処理で、エラーが存在していない場合、「error」変数の中身は「NONE」です。この時は、ユーザーをデータベースに新規登録します。データベースにデータを挿入するSQLは「INSERT文」です。USERテーブルにユーザー名とパスワードを追加(行の追加)しています。
データベースにパスワードを保存するのですが、ここでも文字を直接保存するのではなく、「ハッシュ化」を行って保存します。「generate_passoerd_hash()」関数を利用することで、データベースへのパスワードの保存がより安全になります。
「db.commit」でデータベースの変更を確定します。
⑦「auth.login」へリダイレクト
データベースへユーザーを新規登録したら、「auth.login」へリダイレクトをします。これはまだ出てきていません。
⑧エラーを返します
エラーがある場合、プログラムに埋め込みができるflashでエラーを返します。
⑨return(GET、エラー)
GETメソッドで最初にアクセスしたとき、又はPOSTで、入力フォームの値にエラー発生した場合「auth/register.html」テンプレートを表示します。
ちょっと本格的な仕組みになってきました。
次回も引き続き、ブループリントでユーザーの登録、ログイン処理を実装していきます。このプログラムを実行できるのは、さらに次の項目である「テンプレート」を作成してからですが、気長にプログラムを解析しながら進めていきたいと思います。