flask-loginでログインページを実装したメモ

flask-loginでシンプルなログインページを実装したメモです。

# 環境

|     項目    | バージョン |
|-------------|------------|
| Python      | 3.7        |
| Flask       | 1.0.2      |
| Flask-Login | 0.4.1      |

# ソース

今回は、Bootstrapの無料テンプレートを使ってログイン画面を実装しているのでexampleソースはGitHubに置いてあります。

https://github.com/sky-joker/flask-login-example

Pythonコードは以下の通りです。

```python
#!/usr/bin/env python3
from flask import Flask, request, Response, abort, render_template
from flask_login import LoginManager, login_user, logout_user, login_required, UserMixin
from collections import defaultdict

app = Flask(__name__)
login_manager = LoginManager()
login_manager.init_app(app)
app.config['SECRET_KEY'] = "secret"

class User(UserMixin):
    def __init__(self, id, name, password):
        self.id = id
        self.name = name
        self.password = password

# ログイン用ユーザー作成
users = {
    1: User(1, "user01", "password"),
    2: User(2, "user02", "password")
}

# ユーザーチェックに使用する辞書作成
nested_dict = lambda: defaultdict(nested_dict)
user_check = nested_dict()
for i in users.values():
    user_check[i.name]["password"] = i.password
    user_check[i.name]["id"] = i.id

@login_manager.user_loader
def load_user(user_id):
    return users.get(int(user_id))

@app.route('/')
def home():
    return Response("home: <a href='/login/'>Login</a> <a href='/protected/'>Protected</a> <a href='/logout/'>Logout</a>")

# ログインしないと表示されないパス
@app.route('/protected/')
@login_required
def protected():
    return Response('''
    protected<br />
    <a href="/logout/">logout</a>
    ''')

# ログインパス
@app.route('/login/', methods=["GET", "POST"])
def login():
    if(request.method == "POST"):
        # ユーザーチェック
        if(request.form["username"] in user_check and request.form["password"] == user_check[request.form["username"]]["password"]):
            # ユーザーが存在した場合はログイン
            login_user(users.get(user_check[request.form["username"]]["id"]))
            return Response('''
            login success!<br />
            <a href="/protected/">protected</a><br />
            <a href="/logout/">logout</a>
            ''')
        else:
            return abort(401)
    else:
        return render_template("login.html")

# ログアウトパス
@app.route('/logout/')
@login_required
def logout():
    logout_user()
    return Response('''
    logout success!<br />
    <a href="/login/">login</a>
    ''')

if __name__ == '__main__':
    app.run(host="0.0.0.0",port=8080,debug=True)
```

今回はDBと連携しないのでコードの中にログインするユーザーを書いています。

# 動かし方

pipで `flask-login` をインストールします。
<font color="#FC0107">シェバングは環境に合わせて変更してください</font>

```shell-session
$ pip install flask-login
$ git clone https://github.com/sky-joker/flask-login-example.git
$ cd flask-login-example
$ chmod +x app.py
$ ./app.py
```

# 動作例

まずは、ログインしていない状態で `/protected/` へアクセスして拒否されることを確認しています。
その後にログインしてから再度アクセスして問題なくアクセスできていることを確認します。

![flask-login-example.gif.gif](https://qiita-image-store.s3.amazonaws.com/0/180118/76ba903f-401b-7517-8160-815b191e49db.gif)

# 参考文献

* https://flask-login.readthedocs.io/en/latest/
* https://www.youtube.com/watch?v=2dEM-s3mRLE
* https://infinidum.com/2018/08/18/making-a-simple-login-system-with-flask-login/
* https://www.tutorialrepublic.com/snippets/preview.php?topic=bootstrap&file=simple-login-form