How To Setup Flask-Login

December 16, 2017

Setup Flask-Login

import datetime
from flask import Flask, abort, redirect, url_for, request
from flask_login import LoginManager, UserMixin, AnonymousUserMixin, current_user, login_required, login_user, logout_user

app = Flask(__name__)
app.config.update(
    DEBUG = True,
    SECRET_KEY = 'xxx',
    # conigure login_user(remember=True) valid for 7days, default=1year
    REMEMBER_COOKIE_DURATION = datetime.timedelta(days=7)
)

login_manager = LoginManager()
login_manager.init_app(app)
# show this view on @login_required page if user not login
login_manager.login_view = "login"


# mock database of users
users = [
    {'id': '1', 'username': 'admin', 'password': 'xxx', 'is_admin': True},
    {'id': '2', 'username': 'desmond', 'password': 'yyy', 'is_admin': False}
]

def find_user_by_id(user_id):
    for _user in users:
        if _user['id'] == user_id:
            return _user
    return None

def find_user_by_username(username):
    for _user in users:
        if _user['username'] == username:
            return _user
    return None

# create your custom user class
class LoginUser(UserMixin):
    def __init__(self, id):
        self.id = id

    @property
    def username(self):
        user = self.get_user()
        return user['username']

    @property
    def is_admin(self):
        user = self.get_user()
        return user['is_admin']

    def get_user(self):
        return find_user_by_id(self.id)


class AnonymousUser(AnonymousUserMixin):
    @property
    def username(self):
        return None

    @property
    def is_admin(self):
        return None

    def get_user(self):
        return None

login_manager.anonymous_user = AnonymousUser

# load user from session
@login_manager.user_loader
def load_user(user_id):
    # you can choose to perform authentication here,
    # or overwrite `is_authenticated` for `LoginUser`
    user = find_user_by_id(user_id)
    if not user:
        return None
    return LoginUser(id=user_id)

Setup Flask-Login views for login, logout, etc.

@app.route('/')
def home():
    if not current_user.is_authenticated:
        return 'Please <a href="{0}">login</a>. Test <a href="{1}">private</a>.'.format(url_for('login'), url_for('private'))
    return url_for('private')

@app.route("/login", methods=["GET", "POST"])
def login():
    message = "Login"
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        user = find_user_by_username(username)
        if user:
            if user['password'] == password:
                # remeber=True, user remain login after browser closed
                login_user(LoginUser(user['id']))
                next = request.args.get("next")
                if not next:
                    next = url_for('private')
                return redirect(next)

        message = "Login FAIL"

    return '''
    <p>{0}</p>
    <form action="" method="post">
        <input type="text" name="username" placeholder="username">
        <input type="password" name="password" placeholder="password">
        <input type="submit" value="Login">
    </form>
    '''.format(message)

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return 'Logout OK, <a href="{0}">home</a>'.format(url_for('home'))


@app.route("/private")
@login_required
def private():
    return 'username={0}, is_admin={1}, <a href="{2}">logout</a>'.format(current_user.username, current_user.is_admin, url_for('logout'))
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.