Back to Blog

Flaskでログイン機能を実装する方法を解説【会員登録、ログイン、ログアウト機能】

flask

2024年7月15日

こんにちは!

今回の記事では、Flaskでログイン機能を実装する方法を解説します。

ログイン機能を実装するには、Flask-Loginを利用します。その他にも、データベースやフォームの処理などを設定する必要があります。

Webアプリケーションに必要なログイン機能の実装方法を解説します。

Flaskでログイン機能を実装する方法

ここからは、Flaskでログイン機能を実装する方法を順に説明します。

必要なライブラリのインストール

まず、Flaskとその他の必要なライブラリをインストールします。今回インストールするライブラリには、以下のようなものがあります。

  • Flask-WTF・・・フォーム作成のため
  • Flask-Login・・・ユーザーセッション管理のため
  • SQLAlchemy・・・データベース操作のため
  • Flask-Migrate・・・データベースマイグレーションのため

以下のコマンドを実行してインストールをします。

pip install Flask Flask-WTF Flask-Login Flask-SQLAlchemy Flask-Migrate

ディレクトリ構造

今回作成するアプリは、ホームページ、ログインページ、会員登録ページ、ログアウト機能を実装します。

アプリのディレクトリ構造は以下のようになります。

flask_app/
├── app.py
├── models.py
├── forms.py
├── templates/
│   ├── base.html
│   ├── login.html
│   ├── register.html
│   └── home.html
├── migrations/
└── __init__.py

app.pyの設定

app.pyには、アプリケーションの設定、ルート、ビュー関数などを定義します。

app.pyは、以下のように記述します。

from flask import Flask, render_template, redirect, url_for, flash
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from models import db, User
from forms import LoginForm, RegistrationForm 
import os

app = Flask(__name__)

# Configuration settings
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') or 'mysecret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Initialize extensions
db.init_app(app)
migrate = Migrate(app, db)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

# User loader function
@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# Routes
@app.route('/')
@login_required
def home():
    return render_template('home.html', name=current_user.username)

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user and user.check_password(form.password.data):
            login_user(user)
            flash('ログインに成功しました。')
            return redirect(url_for('home'))
        else:
            flash('ユーザー名またはパスワードが無効です。')
    return render_template('login.html', form=form)

@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash('ログアウトしました。')
    return redirect(url_for('login'))

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('ユーザー登録が完了しました。')
        return redirect(url_for('login'))
    return render_template('register.html', form=form)

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

app.pyの20行目”login_manager = LoginManager(app)”では、Flaskアプリケーションにユーザー認証機能を追加しています。

この設定により、LoginManagerはFlaskアプリケーションのリクエストライフサイクルに統合され、セッションの管理、ログイン状態の確認、リダイレクトの処理などの機能が提供されます。

フォームの定義(form.py)

ログインフォームと登録フォームを定義します。

forms.pyファイルを作成し、以下のように記述します。

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo, ValidationError
from models import User

class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Login')

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
    password = PasswordField('Password', validators=[DataRequired()])
    password2 = PasswordField('Repeat Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Register')

    def validate_username(self, username):
        user = User.query.filter_by(username=username.data).first()
        if user is not None:
            raise ValidationError('Please use a different username.')

ユーザーモデルの定義(models.py)

ユーザーモデルを定義します。

ユーザーの認証情報を保存するためにSQLAlchemyを使用します。

from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

db = SQLAlchemy()

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

データベースの設定やモデルの設定についてはこちらの記事で詳しく解説しています。

テンプレートの設定

テンプレートは、4つ設定します。

  • base.html・・・全ページ共通のヘッダー
  • home.html・・・ホーム画面(ログインしたら閲覧できる)
  • login.html・・・ログイン画面
  • register.html・・・会員登録画面

templates/base.htmlは以下のように設定します。

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Flask Login{% endblock %}</title>
</head>
<body>
    <nav>
        <ul>
            <li><a href="./">Home</a></li>
            {% if current_user.is_authenticated %}
                <li><a href="./logout">Logout</a></li>
            {% else %}
                <li><a href="./login">Login</a></li>
                <li><a href="./register">Register</a></li>
            {% endif %}
        </ul>
    </nav>
    <div>
        {% with messages = get_flashed_messages() %}
            {% if messages %}
                <ul>
                    {% for message in messages %}
                        <li>{{ message }}</li>
                    {% endfor %}
                </ul>
            {% endif %}
        {% endwith %}
        {% block content %}{% endblock %}
    </div>
</body>
</html>

templates/home.htmlは以下のように設定します。

{% extends "base.html" %}
{% block title %}Home{% endblock %}
{% block content %}
    <h2>Home</h2>
    <p>Welcome, {{ name }}!</p>
{% endblock %}

templates/login.htmlは以下のように設定します。

{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block content %}
    <h2>Login</h2>
    <form method="POST" action="">
        {{ form.hidden_tag() }}
        <p>
            {{ form.username.label }}<br>
            {{ form.username(size=32) }}<br>
            {{ form.password.label }}<br>
            {{ form.password(size=32) }}<br>
            {{ form.submit() }}
        </p>
    </form>
{% endblock %}

templates/register.htmlは以下のように設定します。

{% extends "base.html" %}
{% block title %}Register{% endblock %}
{% block content %}
    <h2>Register</h2>
    <form method="POST" action="./register">
        {{ form.hidden_tag() }}
        <p>
            {{ form.username.label }}<br>
            {{ form.username(size=32) }}<br>
            {{ form.password.label }}<br>
            {{ form.password(size=32) }}<br>
            {{ form.password2.label }}<br>
            {{ form.password2(size=32) }}<br>
            {{ form.submit() }}
        </p>
    </form>
{% endblock %}

ここまでで設定は完了です!

Flaskアプリの起動

設定ファイルやテンプレートなどの準備が整ったら、Flaskアプリケーションの起動を行います。

データベースの作成

まず、データベースの作成を行います。以下のコマンドを実行しましょう。

flask db init
flask db migrate -m "Initial migration."
flask db upgrade

コマンドの実行が完了すると、Userテーブルが作成されています。このテーブルにログインするユーザー情報が格納されます。

Flaskアプリの起動

続いて、Flaskアプリの起動を行います。

python app.py

動作確認

Flaskアプリの起動ができたら、ブラウザからアクセスしてみましょう。

まず、http://127.0.0.1:5000/registerにアクセスすると、会員登録ページに移動します。フォームにユーザー名とパスワードを入力してユーザーを作成します。

ユーザーの作成が完了したら、ログインページでログインしてみましょう。

ログインに成功すると、ホーム(http://127.0.0.1:5000/)が閲覧できるようになります。ホームでは、ログインしているユーザー名を出力しています。

ヘッダーメニューのLogoutをクリックすると、ログアウトします。ログアウトした状態では、ホーム画面を閲覧することができず、ログインページへリダイレクトされます。

これで、ログイン機能の実装が完了です!

まとめ

Flaskを使って基本的なログイン機能とユーザー登録機能を実装する方法を解説しました。

この基本的な実装を基に、さらに機能を拡張していくことができます。例えば、パスワードリセット機能やユーザーの役割管理機能などを追加することが考えられます。ぜひ、自分で作りたい機能を作ってみてください!

今回の記事が、あなたのWeb開発のお役に立てれば幸いです。

ここまでお読みいただきありがとうございました。

             

Pythonの基礎から応用まで学べる
Python WebAcademy

Python WebAcademyでは、Pythonの基礎からアーキテクチャなどの応用的な内容まで幅広く学べます。また、ブラウザ上で直接Pythonコードを試すことができ、実践的なスキルを身につけることが可能です。

             Pythonの学習を始める