Bootstrap FreeKB - Flask - Getting Started with Flask Login
Flask - Getting Started with Flask Login

Updated:   |  Flask articles

Flask uses the MVC (Model View Controller) Framework. Just to make this as obvious as possible, I like my Flask apps to have the following.

  • Model -> models.py
  • View -> views.py
  • Controller -> __init__.py

Let's say your Flask app has the following files.

├── main.py
├── database (directory)
│   ├── example.db
├── my-project (directory)
│   ├── __init__.py
│   ├── views.py
│   ├── models.py
│   ├── templates (directory)
│   │   ├── base.html
│   │   ├── home.html
│   │   ├── results.html
│   └── static (directory)
│       └── custom.css

 

Flask-Login can be used to create session objects after a user has been authenticated. First, use pip to install Flask-Login.

pip install Flask-Login

 

This assumes you already have some sort of sign in form that is used to check if a users username and password are valid.

 

In your controller (__init__.py in this example), setup the Login Manager.

  • In this example, from .models import users is used to import the users table from the model (models.py in this example)
  • login_manager.login_view = 'views.SignIn' to use the /SignIn route in the view (views.py in this example)
import sqlite3
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

db = SQLAlchemy()

def app_obj():
    app = Flask(__name__)

    app.config['SECRET_KEY'] = 'some_unique_string_of_data'

    # VIEWS
    from .views import views
    app.register_blueprint(views, url_prefix='/')

    # database
    uri = "sqlite:///example.db"
    app.config['SQLALCHEMY_DATABASE_URI'] = uri
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

    db.init_app(app)

    # LOGIN MANAGER
    from .models import users
    login_manager = LoginManager()
    login_manager.login_view = 'views.SignIn'
    login_manager.init_app(app)

    @login_manager.user_loader
    def load_user(id):
        return users.query.get(int(id))
    
    return app

 

In your model (models.py in this example), let's say you have a table named users. UserMixin is needed to be able to use current_user in your view.

from sqlalchemy import func
from flask_login import UserMixin
from . import db

class users(db.Model, UserMixin):    
    id       = db.Column(db.Integer,     nullable=False, unique=True, primary_key=True)   
    email    = db.Column(db.String(50),  nullable=False, unique=False)
    password = db.Column(db.String(100), nullable=False, unique=False)

 

Your view could have something like this.

from flask import flash, redirect, url_for
from flask_login import login_user, current_user
from . import db

@views.route('/SignIn', methods=['GET', 'POST'])
def signin():
    from .models import users
    data = users.query.filter_by(email=request.form.get('email')).first()

    print(f"data = {data}")

    if data == None:
      print(f"no user found with {email}")
    else:
      print(f"current_user.is_authenticated before login_user = {current_user.is_authenticated}")
      print(f"current_user.is_active before login_user = {current_user.is_active}")
      
      login_user(data)

      print(f"current_user.is_authenticated after login_user = {current_user.is_authenticated}")
      print(f"current_user.is_active after login_user = {current_user.is_active}")

      flash('Successfully Signed In' ,category='primary')
      return redirect(url_for('views.home'))

 

Should return the following. In this example, since the "data" variable has <users 123>, this means there is a result was found in the "users" table with ID 123. Or you could add def is_active(self) return True in your model.

data = <users 123>
current_user.is_authenticated before login_user = False
current_user.is_active before login_user        = False
current_user.is_authenticated after login_user  = True
current_user.is_active after login_user         = True

 

Or perhaps like this.

  • In this example, from .models import users is used to import the users table from the model (models.py in this example)
  • users.query.filter_by(email=request.form.get('email')).first() is used to see if the users email exists in the users table
  • check out my article on check_password_hash
  • login_user is used to create session objects
  • logout_user is used to destroy the session objects
from flask import flash, redirect, url_for
from flask_login import login_user, login_required, logout_user, current_user
from . import db
from werkzeug.security import check_password_hash

@views.route('/SignIn', methods=['GET', 'POST'])
def signin():
    from .models import users
    data = users.query.filter_by(email=request.form.get('email')).first()
    password_hash = check_password_hash(data.password, request.form.get('password'))
    login_user(data)
    flash('Successfully Signed In' ,category='primary')
    return redirect(url_for('views.home'))

@views.route('/SignOut')
@login_required <- only allow access to this route if user is logged in
def signout():
    logout_user()
    flash('Successfully Signed Out' ,category='primary')
    return redirect(url_for('views.home'))

 

If login_user is successful, 2 cookies should be created in the users web browser, remember_token and session.

 

 

On your HTML pages, you should then be able to use current_user to do whatever it is that you want to do when a user has been authenticated.

{% current_user.is_authenticated and current_user.is_active %}
    current_user.is_authenticated = {{ current_user.is_authenticated }}<br />
    current_user.is_active = {{ current_user.is_active }}<br />
    current_user.is_anonymous = {{ current_user.is_anonymous }}<br />
    current_user.get_id = {{ current_user.get_id }}<br />
{% endif %}

 

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 91eba7 in the box below so that we can be sure you are a human.