ウェブサイト検索

Flask-Loginを使用してアプリに認証を追加する方法


紹介

ユーザーがあなたのアプリにログインできるようにすることは、ウェブアプリケーションに追加する最も一般的な機能の1つです。Flask-Loginパッケージを使ってFlaskアプリに認証を追加することができます。

このチュートリアルでは、あなたは:

  • セッション管理にはFlask-Loginライブラリを使用してください。
  • パスワードをハッシュ化するために、組み込みのFlaskユーティリティを使用してください。
  • ログインユーザーのみがアクセスできる保護されたページをアプリに追加してください。
  • Flask-SQLAlchemyを使用してUserモデルを作成します
  • ユーザーがアカウントを作成し、ログインするためのサインアップおよびログインフォームを作成します。
  • 何か問題が発生したときに、ユーザーにフラッシュエラーメッセージを表示する
  • ユーザーのアカウントからの情報を使用してプロフィールページに表示します

ユーザーがログインし、保護されたページにアクセスできるサインアップページとログインページを構築します。Userモデの情報を使用し、ユーザーがログインした際に保護されたページにそれを表示して、プロファイルがどのように見えるかをシミュレートします。

注意: このチュートリアルは範囲が限られており、高度なセッションの持続性については扱っていません。また、プライマリキーのデータ型を変更することや、異なるデータベースシステムへの移行に関する考慮事項も、この入門チュートリアルの範囲外です。

このプロジェクトのソースコードはGitHubで入手できます。

前提条件

このチュートリアルを完了するには、以下が必要です:

  • Pythonにある程度の知識があります。
  • ローカル環境にインストールされたPython。
  • 基本的なLinuxナビゲーションとファイル管理の知識。

こちらは、チュートリアルを完了した後のプロジェクトのファイル構造がどのようになるかを示す図です。

.
└── flask_auth_app
    └── project
        ├── __init__.py       # setup the app
        ├── auth.py           # the auth routes for the app
        ├── db.sqlite         # the database
        ├── main.py           # the non-auth routes for the app
        ├── models.py         # the user model
        └── templates
            ├── base.html     # contains common layout and links
            ├── index.html    # show the home page
            ├── login.html    # show the login form
            ├── profile.html  # show the profile page
            └── signup.html   # show the signup form

チュートリアルを進めるにつれて、これらのディレクトリとファイルを作成します。

このチュートリアルは、sqlite3 v3.36.0、python v3.9.8、flask v2.0.2、flask-login v0.5.0、およびflask-sqlalchemy v2.5.1で確認されました。

ステップ1 — パッケージのインストール

プロジェクトに必要な主なパッケージは3つあります:

  • フラスコ
  • Flask-Login: 認証後のユーザーセッションを管理するためのものです
  • Flask-SQLAlchemy: ユーザーモデルを表現し、データベースとインターフェースを持つための

データベースのために追加の依存関係をインストールする必要がないように、SQLiteを使用します。

まず、プロジェクトディレクトリを作成することから始めます。

  1. mkdir flask_auth_app

次に、プロジェクトディレクトリに移動します。

  1. cd flask_auth_app

Python環境を持っていない場合は、作成したいと思うでしょう。

注: venvの設定については、ローカル環境に関連するチュートリアルを参照してください。

Pythonがあなたのマシンにどのようにインストールされたかによって、あなたのコマンドは次のようになります:

  1. python3 -m venv auth

-mフラグはmodule-name用です。このコマンドはvenvモジュールを実行して、authという名前の新しい仮想環境を作成します。これにより、bin、include、およびlibサブディレクトリを含む新しいディレクトリが作成されます。そして、pyvenv.cfgファイルが作成されます。

次に、次のコマンドを実行してください。

  1. source auth/bin/activate

このコマンドは仮想環境をアクティブにします。

必要なパッケージをインストールするために、次のコマンドを仮想環境から実行してください:

  1. pip install flask flask-sqlalchemy flask-login

パッケージをインストールしたので、メインアプリファイルを作成する準備が整いました。

ステップ2 — メインアプリファイルの作成

まずは project ディレクトリを作成しましょう:

  1. mkdir project

最初のファイルはプロジェクトの __init__.py ファイルです:

  1. nano project/__init__.py

このアプリは、Flaskのアプリファクトリパターンとブループリントを使用します。一つのブループリントは、インデックスや保護されたプロフィールページを含む通常のルートを扱います。もう一つのブループリントは、認証に関連するすべてのことを扱います。実際のアプリでは、機能を好きなように分解できますが、ここで扱う解決策はこのチュートリアルにはうまく機能します。

このファイルはアプリを作成する機能を持ち、データベースを初期化し、ブループリントを登録します。現時点ではあまり機能しませんが、アプリの残りの部分には必要になります。

SQLAlchemyを初期化し、いくつかの設定値を設定し、ここでブループリントを登録する必要があります。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)

    app.config['SECRET_KEY'] = 'secret-key-goes-here'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'

    db.init_app(app)

    # blueprint for auth routes in our app
    from .auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint)

    # blueprint for non-auth parts of app
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app

主要なアプリファイルを入手したので、ルートを追加し始めてください。

ステップ3 — ルートの追加

ルートには、2つの設計図を使用します。

この main_blueprint では、ホームページ (/) とプロフィールページ (/profile) を用意します。

まず、main.pyを作成します:

  1. nano project/main.py

次に、あなたの main_blueprint を追加してください:

from flask import Blueprint
from . import db

main = Blueprint('main', __name__)

@main.route('/')
def index():
    return 'Index'

@main.route('/profile')
def profile():
    return 'Profile'

auth_blueprintには、ログインページ(/login)とサインアップページ(/signup)を取得するためのルートがあります。最後に、アクティブユーザーをログアウトさせるためのログアウトルート(/logout)もあります。

次に、auth.pyを作成します:

  1. nano project/auth.py

次に、あなたの auth_blueprint を追加してください:

from flask import Blueprint
from . import db

auth = Blueprint('auth', __name__)

@auth.route('/login')
def login():
    return 'Login'

@auth.route('/signup')
def signup():
    return 'Signup'

@auth.route('/logout')
def logout():
    return 'Logout'

当面は、login、signup、およびlogoutをテキスト戻り値で定義してください。また、loginとsignupからのPOSTリクエストを処理するためのルートも作成します。このコードは後で見直し、必要な機能を追加します。

ターミナルで、FLASK_APP と FLASK_DEBUG の値を設定できます。

  1. export FLASK_APP=project
  2. export FLASK_DEBUG=1

FLASK_APP 環境変数は、Flask にアプリをどのようにロードするかを指示します。これを create_app がある場所を指すように設定する必要があります。このチュートリアルでは、project ディレクトリを指すことになります。

FLASK_DEBUG 環境変数は 1 に設定することで有効になります。これにより、アプリケーションのエラーがブラウザに表示されるデバッガが有効になります。

flask_auth_app ディレクトリにいることを確認し、その後プロジェクトを実行してください:

  1. flask run

今、ウェブブラウザで、5つの可能なURLにナビゲートして、auth.pyおよびmain.pyで定義されたテキストを確認できます。

たとえば、localhost:5000/profile にアクセスすると、次のように表示されます:プロフィール:

ルートが期待通りに動作していることを確認したら、テンプレートを作成できます。

ステップ4 — テンプレートの作成

次に、アプリで使用されるテンプレートを作成します。これは、実際のログイン機能を実装する前の最初のステップです。

アプリは4つのテンプレートを使用します。

  • index.html
  • プロフィール.html
  • ログイン.html
  • signup.html

各ページに共通するコードを持つ基本テンプレートもあります。この場合、基本テンプレートにはナビゲーションリンクとページの一般的なレイアウトが含まれます。

最初に、projectディレクトリの下にtemplatesディレクトリを作成します:

  1. mkdir -p project/templates

それから base.html を作成します:

  1. nano project/templates/base.html

次に、base.htmlファイルに次のコードを追加してください:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Flask Auth Example</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
</head>

<body>
    <section class="hero is-primary is-fullheight">

        <div class="hero-head">
            <nav class="navbar">
                <div class="container">
                    <div id="navbarMenuHeroA" class="navbar-menu">
                        <div class="navbar-end">
                            <a href="{{ url_for('main.index') }}" class="navbar-item">
                                Home
                            </a>
                            <a href="{{ url_for('main.profile') }}" class="navbar-item">
                                Profile
                            </a>
                            <a href="{{ url_for('auth.login') }}" class="navbar-item">
                                Login
                            </a>
                            <a href="{{ url_for('auth.signup') }}" class="navbar-item">
                                Sign Up
                            </a>
                            <a href="{{ url_for('auth.logout') }}" class="navbar-item">
                                Logout
                            </a>
                        </div>
                    </div>
                </div>
            </nav>
        </div>

        <div class="hero-body">
            <div class="container has-text-centered">
               {% block content %}
               {% endblock %}
            </div>
        </div>
    </section>
</body>

</html>

このコードは、アプリケーションの各ページへのメニューリンクのシリーズを作成します。また、子テンプレートによって上書きできるcontent用のブロックを設定します。

注: このチュートリアルでは、スタイリングとレイアウトの処理にBulmaを使用しています。Bulmaについてより深く知りたい場合は、公式のBulmaドキュメントを読むことをお勧めします。

次に、templates/index.htmlを作成します:

  1. nano project/templates/index.html

新しく作成したファイルに以下のコードを追加して、ページに内容を追加してください。

{% extends "base.html" %}

{% block content %}
<h1 class="title">
  Flask Login Example
</h1>
<h2 class="subtitle">
  Easy authentication and authorization in Flask.
</h2>
{% endblock %}

このコードは、タイトルとサブタイトルを持つ基本的なインデックスページを作成します。

次に、templates/login.htmlを作成します:

  1. nano project/templates/login.html

このコードは、メールとパスワードのフィールドを持つログインページを生成します。また、ログインセッションを「記憶する」ためのチェックボックスもあります。

{% extends "base.html" %}

{% block content %}
<div class="column is-4 is-offset-4">
    <h3 class="title">Login</h3>
    <div class="box">
        <form method="POST" action="/login">
            <div class="field">
                <div class="control">
                    <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                </div>
            </div>

            <div class="field">
                <div class="control">
                    <input class="input is-large" type="password" name="password" placeholder="Your Password">
                </div>
            </div>
            <div class="field">
                <label class="checkbox">
                    <input type="checkbox" name="remember">
                    Remember me
                </label>
            </div>
            <button class="button is-block is-info is-large is-fullwidth">Login</button>
        </form>
    </div>
</div>
{% endblock %}

次に、templates/signup.htmlを作成します:

  1. nano project/templates/signup.html

以下のコードを追加して、email、name、およびpasswordのフィールドを持つサインアップページを作成します:

{% extends "base.html" %}

{% block content %}
<div class="column is-4 is-offset-4">
    <h3 class="title">Sign Up</h3>
    <div class="box">
        <form method="POST" action="/signup">
            <div class="field">
                <div class="control">
                    <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                </div>
            </div>

            <div class="field">
                <div class="control">
                    <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                </div>
            </div>

            <div class="field">
                <div class="control">
                    <input class="input is-large" type="password" name="password" placeholder="Password">
                </div>
            </div>

            <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
        </form>
    </div>
</div>
{% endblock %}

次に、templates/profile.htmlを作成します:

  1. nano project/templates/profile.html

このコードを追加して、タイトルがアンソニーにハードコーディングされたページを作成します:

{% extends "base.html" %}

{% block content %}
<h1 class="title">
  Welcome, Anthony!
</h1>
{% endblock %}

後でこのコードに戻って、任意のユーザーに動的に挨拶します。

テンプレートを追加したら、それぞれのルートの返り値をテキストの代わりにテンプレートを返すように更新できます。

次に、main.pyを更新し、インポート行とindexおよびprofileのルートを修正します。

from flask import Blueprint, render_template
...
@main.route('/')
def index():
    return render_template('index.html')

@main.route('/profile')
def profile():
    return render_template('profile.html')

さて、auth.pyを更新して、loginとsignupのインポート行とルートを修正します:

from flask import Blueprint, render_template
...
@auth.route('/login')
def login():
    return render_template('login.html')

@auth.route('/signup')
def signup():
    return render_template('signup.html')

これらの変更を行った後、/signupに移動するとサインアップページは次のように見えます:

あなたは/、/login、および/profileのページにも移動できます。

今は/logoutをそのままにしておいてください。後でテンプレートは表示されません。

ステップ5 — ユーザーモデルの作成

ユーザーモデルは、アプリがユーザーを持つことを意味しています。このチュートリアルでは、email アドレス、password、name のフィールドが必要になります。将来のアプリケーションでは、ユーザーごとにもっと多くの情報を保存したいと考えるかもしれません。誕生日、プロフィール画像、場所、または任意のユーザーの好みなどを追加できます。

Flask-SQLAlchemyで作成されたモデルは、クラスとして表現され、それがデータベース内のテーブルに変換されます。これらのクラスの属性は、そのテーブルの列に変わります。

Userモデルを作成します:

  1. nano project/models.py

Userモデルを定義します:

from . import db

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000))

このコードは、id、email、password、およびnameのカラムを持つUserを定義しています。

ユーザーモデルを作成したので、データベースの設定に移ることができます。

ステップ 6 — データベースの設定

SQLiteデータベースを使用します。自分でSQLiteデータベースを作成することもできますが、Flask-SQLAlchemyにそれを行わせましょう。すでに__init__.pyファイルでデータベースのパスが指定されているので、Flask-SQLAlchemyにPython REPLでデータベースを作成するように指示する必要があります。

仮想環境にまだいることと、flask_auth_appディレクトリにいることを確認してください。

アプリを停止してPython REPLを開くと、dbオブジェクトのcreate_allメソッドを使用してデータベースを作成できます:

  1. from project import db, create_app, models
  2. db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

注意: Python インタプリタの使用が初めての場合は、公式ドキュメントを参照してください。

プロジェクトディレクトリにdb.sqliteファイルが表示されるようになります。このデータベースにはユーザーテーブルが含まれています。

ステップ7 — 認証機能の設定

サインアップ機能では、ユーザーがフォームに提出したデータを取得し、それをデータベースに追加します。同じメールアドレスを持つユーザーが既にデータベースに存在しないことを確認する必要があります。存在しない場合は、データベースに追加する前にパスワードをハッシュ化する必要があります。

注: パスワードをプレーンテキストで保存することは、良くないセキュリティプラクティスと見なされます。パスワードを安全に保つためには、一般的に複雑なハッシュアルゴリズムとソルトが必要です。

最初に、POSTフォームデータを処理するための第二の関数を追加しましょう。ユーザーから渡されたデータを収集します。

auth.pyを更新し、インポート行を修正してsignup_postを実装してください:

from flask import Blueprint, render_template, redirect, url_for
...
@auth.route('/signup')
def signup():
    return render_template('signup.html')

@auth.route('/signup', methods=['POST'])
def signup_post():
    # code to validate and add user to database goes here
    return redirect(url_for('auth.login'))

関数を作成し、リダイレクトを追加してください。これにより、成功したサインアップとログインページへの遷移を含むユーザー体験が提供されます。

では、ユーザー登録に必要な残りのコードを追加しましょう。リクエストオブジェクトを使用してフォームデータを取得します。

auth.pyを更新し続けて、インポートを追加し、signup_postを実装します:

from flask import Blueprint, render_template, redirect, url_for, request
from werkzeug.security import generate_password_hash, check_password_hash
from .models import User
from . import db
...
@auth.route('/signup', methods=['POST'])
def signup_post():
    # code to validate and add user to database goes here
    email = request.form.get('email')
    name = request.form.get('name')
    password = request.form.get('password')

    user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database

    if user: # if a user is found, we want to redirect back to signup page so user can try again
        return redirect(url_for('auth.signup'))

    # create a new user with the form data. Hash the password so the plaintext version isn't saved.
    new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))

    # add the new user to the database
    db.session.add(new_user)
    db.session.commit()

    return redirect(url_for('auth.login'))

このコードは、同じメールアドレスを持つユーザーがデータベースに存在するかどうかを確認します。

ステップ8 — サインアップメソッドのテスト

サインアップ方法が完了したので、新しいユーザーを作成できるようになります。ユーザーを作成するためのフォームをテストしてみましょう。

サインアップが成功したかどうかを確認する方法は2つあります:

  • データベースビューアを使用して、テーブルに追加された行を確認できます。
  • または、同じメールアドレスで再登録を試みることができ、エラーが出た場合は最初のメールが正しく保存されたことがわかります。

ユーザーにメールが既に存在することを知らせ、ログインページに移動するように指示するコードを追加しましょう。flash関数を呼び出すことで、次のリクエストにメッセージを送信できます。この場合、リダイレクトがそのリクエストです。ユーザーがリダイレクトされるページは、そのテンプレート内でそのメッセージにアクセスできるようになります。

まず、サインアップページにリダイレクトする前に flash を追加してください。

from flask import Blueprint, render_template, redirect, url_for, request, flash
...
@auth.route('/signup', methods=['POST'])
def signup_post():
    ...
    if user: # if a user is found, we want to redirect back to signup page so user can try again
        flash('Email address already exists')
        return redirect(url_for('auth.signup'))

テンプレートにフラッシュメッセージを表示させるには、このコードをフォームの前に追加できます。

...
{% with messages = get_flashed_messages() %}
{% if messages %}
    <div class="notification is-danger">
        {{ messages[0] }}. Go to <a href="{{ url_for('auth.login') }}">login page</a>.
    </div>
{% endif %}
{% endwith %}
<form method="POST" action="/signup">

このコードは、メールアドレスがすでにデータベースに存在する場合に "メールアドレスはすでに存在します。ログインページに移動してください。" というメッセージを表示します。

この時点で、アプリケーションを実行し、すでに存在するメールアドレスでサインアップしようとすることができます。

ステップ9 — ログイン方法の追加

ログイン方法はサインアップ機能と似ています。この場合、入力されたemailアドレスがデータベースに存在するかどうかを比較します。存在する場合は、ユーザーが提供したpasswordをハッシュ化し、データベース内のハッシュ化されたpasswordと比較して、ユーザーが正しいpasswordを入力したかどうかをテストします。両方のハッシュ化されたpasswordが一致したとき、ユーザーが正しいpasswordを入力したことがわかります。

ユーザーがパスワードチェックを通過すると、彼らが正しい資格情報を持っていることがわかり、Flask-Loginを使用してログインさせることができます。login_userを呼び出すことで、Flask-Loginはそのユーザーのためのセッションを作成し、ユーザーがログインしている限りそのセッションは持続します。これにより、ユーザーは保護されたページを閲覧することができます。

POSTで送信されたデータを処理するための新しいルートを作成することから始めることができます。そして、ユーザーが正常にログインしたときにプロフィールページにリダイレクトします:

...
@auth.route('/login')
def login():
    return render_template('login.html')

@auth.route('/login', methods=['POST'])
def login_post():
    # login code goes here
    return redirect(url_for('main.profile'))

さて、ユーザーが正しい資格情報を持っているか確認する必要があります。

...
@auth.route('/login', methods=['POST'])
def login_post():
    # login code goes here
    email = request.form.get('email')
    password = request.form.get('password')
    remember = True if request.form.get('remember') else False

    user = User.query.filter_by(email=email).first()

    # check if the user actually exists
    # take the user-supplied password, hash it, and compare it to the hashed password in the database
    if not user or not check_password_hash(user.password, password):
        flash('Please check your login details and try again.')
        return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page

    # if the above check passes, then we know the user has the right credentials
    return redirect(url_for('main.profile'))

テンプレートにブロックを追加して、ユーザーが表示されたメッセージを見ることができるようにしましょう:

...
{% with messages = get_flashed_messages() %}
{% if messages %}
    <div class="notification is-danger">
        {{ messages[0] }}
    </div>
{% endif %}
{% endwith %}
<form method="POST" action="/login">

ユーザーが正常にログインしたと言う能力はありますが、ユーザーがログインするものは何もありません。

Flask-Loginはユーザーセッションを管理できます。まず、UserMixinをユーザーモデルに追加します。UserMixinはFlask-Loginの属性をモデルに追加するため、Flask-Loginがそれと連携できるようになります。

from flask_login import UserMixin
from . import db

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000))

次に、ユーザーローダーを指定する必要があります。ユーザーローダーは、Flask-Loginにセッションクッキーに保存されているIDから特定のユーザーを見つける方法を教えます。これを、create_app関数の中にinitコードと一緒に追加します:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
...
def create_app():
    ...
    db.init_app(app)

    login_manager = LoginManager()
    login_manager.login_view = 'auth.login'
    login_manager.init_app(app)

    from .models import User

    @login_manager.user_loader
    def load_user(user_id):
        # since the user_id is just the primary key of our user table, use it in the query for the user
        return User.query.get(int(user_id))

最後に、プロファイルページにリダイレクトする前にlogin_user関数を追加してセッションを作成します:

from flask_login import login_user
from .models import User
from . import db
...
@auth.route('/login', methods=['POST'])
def login_post():
    ...
    # if the above check passes, then we know the user has the right credentials
    login_user(user, remember=remember)
    return redirect(url_for('main.profile'))

Flask-Loginを設定したら、/loginルートを使用します。すべてが整っていれば、プロフィールページが表示されます。

この時点で、アプリケーションを実行し、ログインを試みることができます。

ステップ10 — ページの保護

あなたの名前がアンソニーでない場合、プロフィールページに間違った名前が表示されることに気づくでしょう。目標は、プロフィールにデータベースの名前を表示することです。ページを保護し、ユーザーのデータにアクセスしてnameを取得する必要があります。

Flask-Loginを使用してページを保護するには、ルートと関数の間に@login_requiredデコレーターを追加します。これにより、ログインしていないユーザーはルートを見ることができなくなります。もしユーザーがログインしていない場合、Flask-Loginの設定に従って、ログインページにリダイレクトされます。

@login_requiredデコレータで装飾されたルートでは、関数内でcurrent_userオブジェクトを使用することができます。このcurrent_userはデータベースのユーザーを表し、ドット表記を使用してそのユーザーのすべての属性にアクセスできます。例えば、current_user.email、current_user.password、current_user.name、およびcurrent_user.idは、ログインしているユーザーのデータベースに保存されている実際の値を返します。

現在のユーザーのnameを使用して、テンプレートに送信しましょう:

from flask import Blueprint, render_template
from flask_login import login_required, current_user
from . import db
...
@main.route('/profile')
@login_required
def profile():
    return render_template('profile.html', name=current_user.name)

次に、profile.htmlファイルでページを更新してnameの値を表示します:

...
<h1 class="title">
  Welcome, {{ name }}!
</h1>

ユーザーがプロフィールページを訪れると、彼らの名前で歓迎されます。

ログアウトビューを更新するには、ログアウト用のルートでlogout_user関数を呼び出します:

from flask_login import login_user, login_required, logout_user
...
@auth.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('main.index'))

@login_requiredデコレーターを使用してください。最初からログインしていないユーザーをログアウトすることは意味がないからです。

ユーザーがログアウトした後、再度プロフィールページを表示しようとすると、エラーメッセージが表示されます:

これは、Flask-Loginがユーザーがページにアクセスできない場合にメッセージを表示するためです。

最後にやるべきことは、テンプレートにifステートメントを入れて、ユーザーに関連するリンクのみを表示することです:

...
<div class="navbar-end">
    <a href="{{ url_for('main.index') }}" class="navbar-item">
        Home
    </a>
    {% if current_user.is_authenticated %}
    <a href="{{ url_for('main.profile') }}" class="navbar-item">
        Profile
    </a>
    {% endif %}
    {% if not current_user.is_authenticated %}
    <a href="{{ url_for('auth.login') }}" class="navbar-item">
        Login
    </a>
    <a href="{{ url_for('auth.signup') }}" class="navbar-item">
        Sign Up
    </a>
    {% endif %}
    {% if current_user.is_authenticated %}
    <a href="{{ url_for('auth.logout') }}" class="navbar-item">
        Logout
    </a>
    {% endif %}
</div>

ユーザーがログインする前に、ログインまたはサインアップのオプションがあります。ログイン後は、プロフィールに移動するか、ログアウトできます。

これで、認証機能を備えたアプリを成功裏に構築しました。

結論

このチュートリアルでは、Flask-LoginとFlask-SQLAlchemyを使用してアプリのログインシステムを構築しました。最初にユーザーモデルを作成してユーザー情報を保存することで、ユーザーを認証する方法について説明しました。次に、フォームから取得したパスワードをハッシュ化し、それをデータベースに保存されているパスワードと比較して、ユーザーのパスワードが正しいかどうかを確認する必要がありました。最後に、@login_requiredデコレーターをプロファイルページに使用することでアプリに認可を追加し、ログインしているユーザーのみがそのページを見ることができるようにしました。

このチュートリアルで作成したものは、小規模なアプリには十分ですが、最初からより多くの機能を望むのであれば、Flask-Loginライブラリの上に構築されたFlask-UserまたはFlask-Securityライブラリのいずれかを検討することをお勧めします。

関連記事: