【#2】FlaskアプリにAuth0つけようとしたらapp.pyがぶっ壊れた話
Flaskは1ファイルで済むって言ったやつ出てこい
はじめに
本番環境に公開するためにAuth0入れてみたけどapp.pyが肥大化して詰んだ。
当初はAuth0をapp.pyに直接投入していたが、ルーティングぐちゃぐちゃになってページが開けなくなったので泣く泣く分割。
ハマった知見とかも共有しときます。
1. フル装備app.pyの地獄
.
├── static
│ └── style.css
├── templates
│ ├── index.html
│ ├── report.html
│ └── layout.html
├── .dockerignore
├── .env
├── .envsample
├── .gitignore
├── app.py
├── README.md
└── requirements.txt
このapp.pyに初期画面、PDFプレビュー画面、認証画面、APIの各ルーティングをすべて入れて@require_authでロックを掛けた結果、想定通りにページが開けなくなって撃沈。
整理しきれないので泣く泣くapp.pyを分割することにした。
@app.route("/generate_pdf")
@require_auth
def pdf(): ...
@app.route("/login")
@require_auth
def login(): ...
2. 構成と認証をちゃんと分離
.
├── papyrus
│ ├── __init__.py
│ ├── api_routes.py
│ ├── auth.py
│ ├── auth_routes.py
│ ├── db.py
│ └── routes.py
├── static
│ └── style.css
├── templates
│ ├── index.html
│ ├── report.html
│ └── layout.html
├── .dockerignore
├── .env
├── .env.sample
├── .gitignore
├── README.md
├── requirements.txt
└── run.py
改修前:app = Flask(__name__)をグローバル変数定義して使用
改修後:create_app()を導入し、app.pyの役割を分割
from papyrus import create_app
from dotenv import load_dotenv
load_dotenv()
app = create_app()
if __name__ == "__main__":
app.run(debug=True)
from flask import Flask
from papyrus.routes import register_routes
from papyrus.api_routes import register_api_routes
from papyrus.auth import init_auth
from papyrus.auth_routes import register_auth_routes
from .db import init_db
from dotenv import load_dotenv
import os
load_dotenv()
def create_app():
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
TEMPLATE_DIR = os.path.join(BASE_DIR, '../templates')
app = Flask(__name__, template_folder=TEMPLATE_DIR)
app.secret_key = os.getenv("FLASK_SECRET_KEY")
init_auth(app)
init_db(app)
register_routes(app)
register_api_routes(app)
register_auth_routes(app)
return app
ポイント
-
load_dotenv()はapp = Flask(__name__)よりも前で実行-
.envファイルの情報が抜けるとcreate_app()でエラー
-
-
app = Flask(__name__)だとtemplates\のファイルを読み込んでくれないので、中にtemlate_folerを設定して明示的にディレクトリ指定する。 -
create_app()内で読み込むルーティング関数は、必要なものすべてそろっているか確認する。
3. Auth0導入
Auth0にログインする。アカウントがなければ作る。
「使用を開始」>「アプリケーションの開始」をクリック

「一般的なWebアプリケーション」を選択する。

Pythonを選択

「クイックスタート」を選び下へスクロール

「Configure your.env file」をコピーしてAPP_SECRET_KEY以外を.envに貼りつけ

「設定」>「アプリケーションのURI」欄に入力

# 許可するコールバックURL
http://localhost:5000/callback
# 許可するログアウトURL
http://localhost:5000/logout
そして...Auth0と連携成功


Googleアカウントと連携していると警告が出る(本番up禁止!)
ターミナルでpython3 -c 'import secrets; print(secrets.token_urlsafe(32))'を実行し、その結果を.envのFLASK_SECRET_KEY=に貼りつけ
4. 他の問題点の解消
元のapp.pyでは、納品リストをグローバル変数 delivery_list = [] として定義していた。
しかしこの実装では、複数ユーザーが同時にアクセスした場合に納品リストの内容が全ユーザー間で共有されてしまうため、セッションごとの分離ができていなかった。
この問題を解消するため、Flaskのセッション(session)を使用して、ユーザーごとにdelivery_listを個別管理するよう変更した。
変更後の実装
# GET: 納品リストの表示
@app.route("/index")
@requires_auth
def index():
form_data = {}
delivery_list = session.get("delivery_list", [])
return render_template("index.html", delivery_list=delivery_list, form_data=form_data)
# POST: 納品リストの更新
@app.route("/index", methods=["POST"])
@requires_auth
def handle_submit():
form_data = {}
delivery_list = session.get("delivery_list", [])
action = request.form.get("action")
# ここで delivery_list を編集してから session に戻す処理を書く(省略)
session["delivery_list"] = delivery_list
return render_template("index.html", delivery_list=delivery_list, form_data=form_data)
5. おわりに
最終的にAuth0取付できて、次回予定の本番環境構築準備ができた。
app.pyオンリーの構成がapp.py分割, create_app()導入, Auth0導入, セッション管理で本格構成にすることができた。
次はVPSに上げて本番環境の構築を試したい。
Discussion