↓ メインコンテンツへスキップ

Flask-Login によるユーザー認証

概要
#

Flask-Login を用いたセッションベースの認証機能の実装。ユーザーモデルへの UserMixin 継承、セッション復元用の user_loader、Werkzeug を用いた安全なパスワードハッシュ化と照合についてのまとめ。

参考ブログ記事
#


1. ユーザークラスとパスワードハッシュ化
#

werkzeug.security の関数を用いて平文パスワードを保存しない設計にする。

 1from flask_login import UserMixin
 2from werkzeug.security import generate_password_hash, check_password_hash
 3from app import db
 4
 5class User(UserMixin, db.Model):
 6    id = db.Column(db.Integer, primary_key=True)
 7    username = db.Column(db.String(80), unique=True, nullable=False)
 8    password_hash = db.Column(db.String(256), nullable=False)
 9
10    def set_password(self, password):
11        self.password_hash = generate_password_hash(password)
12
13    def check_password(self, password):
14        return check_password_hash(self.password_hash, password)

2. LoginManager の初期化と user_loader
#

1from flask_login import LoginManager
2
3login_manager = LoginManager()
4login_manager.login_view = "auth.login"  # 未認証時にリダイレクトするエンドポイント
5
6@login_manager.user_loader
7def load_user(user_id):
8    return User.query.get(int(user_id))

3. ログイン・ログアウト処理とアクセス制御
#

 1from flask import render_template, redirect, url_for, flash, request
 2from flask_login import login_user, logout_user, login_required, current_user
 3
 4@bp.route("/login", methods=["GET", "POST"])
 5def login():
 6    if current_user.is_authenticated:
 7        return redirect(url_for("main.index"))
 8
 9    if request.method == "POST":
10        username = request.form.get("username")
11        password = request.form.get("password")
12        user = User.query.filter_by(username=username).first()
13
14        if user and user.check_password(password):
15            login_user(user)
16            next_page = request.args.get("next")
17            return redirect(next_page or url_for("main.index"))
18        flash("ユーザー名またはパスワードが無効です。")
19
20    return render_template("auth/login.html")
21
22@bp.route("/logout")
23@login_required
24def logout():
25    logout_user()
26    return redirect(url_for("main.index"))

ここに掲載する記事はまだありません。