2018秋の無料相談会
2018秋の無料相談会
2018.08.31

1.0系が出てけっこう経ったけど「Flask」でログイン機能をつけるまでの手順を紹介します

まさくに

こんにちは。バックエンドエンジニアのまさくにです。

最近はPHPばかりではなく、Pythonの案件もいくつか携わらせていただいています。「2018年はPythonにもっと触りたい」という目標が達せられそうで嬉しいです。

また、pyenv、virtualenv、pipだけではなく、pipenvというパッケージ管理もにわかに耳に入るようになりました。新しいものもどんどん取り入れていきたいですね(と、ぢっと手を見る)。

さて、僕自身がいま使っているのがFlaskです。PHPを触っていると気づかないのですが、まだまだ日本語のナレッジが少ないですね……。Stack OverFlowに助けられ、誰かの書いたGithub上のコードに助けられ、右往左往しながらいろいろやっている最中ですが、今回はFlaskでログイン機能を追加したのでその手順をご紹介したいと思います。
 

まずはFlaskを動かしてみる

とりあえずFlaskをpipでインストールし、動かしてみます。環境はmacOS High SierraでpyenvによってPython 3.6.5がインストールされている環境です。

$ pip install flask
・
・
・
Installing collected packages: flask
Successfully installed flask-1.0.2

Flaskは4月に1.0.1のstable版が出て、案件で使っていた僕は俄然安心しました。適当なディレクトリでQuickstartにも書かれている「A Minimal Application」を作ります。

# hello.py
from flask import Flask
app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello, World!'

Minimalというだけあって記述量はごくわずかです。このスクリプトをビルトインサーバーで動かしてみます。環境はdevelopment。こうすることでエラーがあった場合、ブラウザ上でエラーを確認することができます。

$ FLASK_ENV=development FLASK_APP=hello.py flask run
 * Serving Flask app "hello.py" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 150-239-588

立ち上がりました。ここからFlask-Loginを導入していきます。

ページをテンプレートから開くようにする

ログインの機能を追加するために(自分で作ってもいいのですが)、ひとまず世界のどこかの天才が作ったライブラリ(エクステンション)を使用することにします。このページにFlaskのエクステンションが並べられていますので、その中からFlask-Loginを選んでpipでインストールします。

ito_masakuni@lig-mi % pip install flask-login
Collecting flask-login
・
・
・
Installing collected packages: flask-login
  Running setup.py install for flask-login ... done
Successfully installed flask-login-0.4.1

とりあえずFlask-Loginを使うために下記のようにコードを作成し、ページを作ってしまいます。ログインページとダッシュボードのページがあって、ダッシュボードのページはログインをしなければ見られない仕様のつもりです。

# hello-login.py
from flask import Flask, render_template, redirect, url_for
from flask_login import LoginManager, logout_user
app = Flask(__name__)

# flask-loginを設定
login_manager = LoginManager()
login_manager.init_app(app)


@app.route('/', methods=['GET'])
def form():
    return render_template('login.html')


@app.route('/login', methods=['POST'])
def login():
    return redirect(url_for('dashboard'))


@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('login'))


@app.route('/dashboard', methods=['GET'])
def dashboard():
    return render_template('dashboard.html')
# login.html
<html>
<head></head>
<body>
    <form action="login" method="post">
        <div>
            email <input type="text" name="email">
        </div>
        <div>
            password <input type="password" name="password">
        </div>
        <div>
            <input type="submit">
        </div>
    </form>
</body>
</html>
# dashboard.html
<html>
<head></head>
<body>
    <div>クラスのみんなには内緒だよ</div>
</body>
</html>

おもむろに起動して、ダッシュボードを開いてしまいましょう。

$ FLASK_ENV=development FLASK_APP=hello-login.py flask run
 * Serving Flask app "hello-login.py" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 150-239-588

あ、ダッシュボードが見えちゃいましたね。まぁそりゃそうです。ログインの機能をまだつけていないのです。

ログイン機能を追加する

下記のように User.py を追加し、hello-login.py を変更することで、ログインの機能を追加していきます。

# User.py
from flask_login import UserMixin


class User(UserMixin):
    # 追加
    # ユーザーが一意となるIDを取得できるメソッドが必要
    # 今回は無理やり1を渡す
    def get_id(self):
        return 1
# hello-login.py
from flask import Flask, render_template, redirect, url_for
from flask_login import LoginManager, login_user, login_required
from user import User

app = Flask(__name__)

# 追加
# セッションを使うためにシークレットキーが必要です
app.secret_key = 'secret key'

# flask-loginを設定
login_manager = LoginManager()
login_manager.init_app(app)


@app.route('/login', methods=['GET'])
def form():
    return render_template('login.html')


@app.route('/login', methods=['POST'])
def login():
    user = User()
    login_user(user)
    return redirect(url_for('dashboard'))


# 追加
# @login_requiredをつけることによって要ログインになります
@app.route('/dashboard', methods=['GET'])
@login_required
def dashboard():
    return render_template('dashboard.html')

# 追加
# セッションからUserを引き当てるときのコールバックです
# ここではテストなのでUser()をそのまま渡していますが、
# return User.get(user_id) などでUserの引き当てを行うものです。
@login_manager.user_loader
def load_user(user_id):
        return User()

それではダッシュボードをログイン前に開いてみましょう。

期待通り、ログインしないとページが閲覧できない仕様になりました。ログインページからログインするとダッシュボードも開くことができるので、正しく動いているようです。

まとめ

まぁ正直Flaskはミニマルなフレームワークなので、自由度が高いぶん自分でもけっこう書かなきゃならない印象なのですが、エクステンションを使うことでその労力が激減できますね。1.0系が出たということで、今後案件や社内ツールなどに積極的に導入していきたいと思います(と、ぢっと手を見る)。それでは、バックエンドエンジニアのまさくにでした。