LoginSignup
2
1

More than 3 years have passed since last update.

認証機能作成の作成

Last updated at Posted at 2021-01-11

はじめに

Flaskを使用して1からアプリケーションを作り、必要な技術を学んでいただけるようにまとめています。

認証機能の作成

ナビゲーションバーの作成

index.htmlに、ナビゲーションバー(ログイン、ログアウト)のリンクを追加します。
jinjaテンプレートに変更しつつナビゲーションバーを追加します。

src/templates/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" 
          href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
          integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
          crossorigin="anonymous">
    <title>Flask App</title>
</head>
<body>
    <div class="container">
        <nav class='navbar navbar-expand-lg navbar-light bg-light'>
            <a class="navbar-brand" href="/">タイトル</a>
            <button 
                class="navbar-toggler" 
                type="button" 
                data-toggle="collapse" 
                data-target="#nabvarNav"
                aria-controls="navbarNav"
                aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="nav navbar-nav navbar-lighy">
                    <li class="nav-item">
                        <a class="nav-link" href="/login">LogIn</a>
                    </li>
                </ul>
            </div>
        </nav>
        {% block body %}{% endblock %}
        <div class="blog-body">
            投稿がありません。
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
            integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
            crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
            integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" 
            crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" 
            integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" 
            crossorigin="anonymous"></script>
</body>
</html>

ログインフォームの作成

src/templates/login.html
{% extends "./index.html" %}

{% block body %}

<div class="blog-body">
    <form action="/login" method="POST">
        <div class="form-group">
            <label for="InputTitle">ユーザ名</label>
            <input type="text" class="form-control" id="InputTitle" name="username">
        </div>
        <div class="form-group">
            <label for="InputPassword">パスワード</label>
            <input type="password" class="form-control" id="InputPassword" name="password">
        </div>
        <button type="submit" class="btn btn-primary">ログイン</button>
    </form>
</div>
{% endblock %}
src/views.py
from src import app
from flask import render_template

@app.route('/')
def index():
    return render_template('index.html')

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

こんな感じの画面が作成できたかと思います。
python-flask3.png

認証機能の作成

ユーザ情報はいったんコード上で適当に作成して、そのユーザでログインされたら画面を遷移し、失敗したらそのままsignin画面に戻るという処理を実装していきます。

  • sessionの追加

このセッションでは以下を実現します。
1. ログイン成功時、サーバー側からsession情報をフロントエンドに返す。
2. フロントエンドはsession情報をcookie領域に保存する。
3. その後は、フロントエンドはそのsession情報でリクエストし、サーバー側はその情報が正しいか確認することで、ログインしているかどうかを判別する。

※ Flaskでは、sessionという変数でセッション情報を扱うことができる。

ログイン成功後にsession['logged_in']=Trueとすることでsession中のlogged_inという値がtrueにセットされる。
以後、この値をリクエストの旅にチェックすることで、ログインしているかの判別ができる。

サインアウトしたらsession情報を削除する。

  • session keyの設定

secretkeyを使用して、session情報が暗号化される。
(※ 今回は簡易的なものにしていますが、本番環境などではランダムに設定してください。)

__init__.py
from flask import Flask

app = Flask(__name__)
app.config["SECRET_KEY"] = b'_5#y2L"F4Q8z\n\xec]dasfe/'

import src.views
  • API側でのflashの追加

flashという機能を使用して、サインイン成功、失敗、サインアウトなどの各アクションごとにアクション結果をメッセージとして表示します。

  • url_forの使用

urlは現在['/login']など、リンクのパスを直接記載している。これは、開発が進むにつれ、リンクのパスが変更される可能性がある。
そのときに、修正する箇所が増え大変になります。
そこで、[url_for]メソッドを利用する。これを使用すると直接リンクではなく、メソッド名を指定するだけで自動的にリンクしてくれます。

src/views.py
from src import app
from flask import flash
from flask import redirect
from flask import request
from flask import render_template
from flask import url_for
from flask import session


User = {
    'username': 'test',
    'password': 'testpass'
}

@app.route('/')
def index():
    if not session.get('logged_in'):
        return redirect('/login')
    return render_template('index.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        if request.form['username'] != User['username']:
            flash(f'ユーザ名が異なります')
        elif request.form['password'] != User['password']:
            flash(f'パスワードが異なります')
        else:
            session['logged_in'] = True
            flash('ログインしました')
            return redirect('/')
    return render_template('login.html')

@app.route('/logout', methods=['GET'])
def logout():
    session.pop('logged_in', None)
    flash('ログアウトしました')
    return redirect('/')
src/templates/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" 
          href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
          integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
          crossorigin="anonymous">
    <title>Flask App</title>
</head>
<body>
    <div class="container">
        <nav class='navbar navbar-expand-lg navbar-light bg-light'>
            <a class="navbar-brand" href="{{ url_for('index') }}">タイトル</a>
            <button 
                class="navbar-toggler" 
                type="button" 
                data-toggle="collapse" 
                data-target="#nabvarNav"
                aria-controls="navbarNav"
                aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="nav navbar-nav navbar-lighy">
                    {% if not session.logged_in %}
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('login') }}">LogIn</a>
                    </li>
                    {% else %}
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
                    </li>
                    {% endif %}
                </ul>
            </div>
        </nav>
        {% for message in get_flashed_messages() %}
        <div class="alert alert-info" role="alert">
            {{ message }}
        </div>
        {% endfor %}
        <div>
            {% block body %}{% endblock %}
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
            integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
            crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
            integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" 
            crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" 
            integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" 
            crossorigin="anonymous"></script>
</body>
</html>
src/templates/login.html
{% extends "./index.html" %}

{% block body %}

<div class="blog-body">
    <form action="{{ url_for('login') }}" method="POST">
        <div class="form-group">
            <label for="InputTitle">ユーザ名</label>
            <input type="text" class="form-control" id="InputTitle" name="username">
        </div>
        <div class="form-group">
            <label for="InputPassword">パスワード</label>
            <input type="password" class="form-control" id="InputPassword" name="password">
        </div>
        <button type="submit" class="btn btn-primary">ログイン</button>
    </form>
</div>
{% endblock %}

【入力ミス】
スクリーンショット 2020-12-03 23.49.48.png

スクリーンショット 2020-12-03 23.52.45.png

【サインイン成功時】
スクリーンショット 2020-12-03 23.53.40.png

【サインアウト時】
スクリーンショット 2020-12-03 23.54.01.png

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1