In this article, I will be showing you how to build a simple web app with user authentification or login using flask.
This app will have the following features:
- Users will be able to sign up using their email addresses and also create a password.
- Once a user is signed in, they are registered in the database.
- If any user tries to sign in with credentials that already exist in the database, an error message will be returned notifying them.
- The app will have a remember me function to remember users so they don't always have to enter their passwords to login to the app.
- When logged in, a user will be able to see other routes of the app like profile and sign out.
- When signed out, the user can only see the home, Login and signup routes.
Alright lets get coding.
The first step is to fire up the IDE of choice.
Then create a project folder and then set up a virtual environment in which we will add the different dependencies for the app.
Install the necessary packages such as flask, flask-login(which is used for the user login and authentication), flask-sqlalchemy which is used to create a database to store the data.
Once all that is set up, create a new python file and call it init.py
. This will initialise the app.
Open the init.py
file and import the following packages;
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
Flask provides a lightweight framework for building our web app.
SQLAlchemy is used to create the database to store user data such as emails and passwords.
Checkout the official documentation here to know about flask-SQLAlchemy.
flask-login provides user session management for flask. It handles common tasks such as logging in, logging out and remembering users' sessions . Be sure to check out the official flask-login documentation here for more information about it.
Next, we will create a function to initialize the database using SQLAlchmemy as shown in the code snippet below.
Initialise SQLAlchemy so we can use it later.
db = SQLAlchemy()
Create a function called create_app
and create the flask instance and also add other configurations for the database.
def create_app():
app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Qz\k\xec]/'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db.init_app(app)
create a variable called login_manager
to create a Login Manager instance to manage user login.
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
Then create another python file called models.py
to store information about the users.
The model created is constituted of class which is translated into tables in our database. Each of the attributes are transformed into columns for the table.
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
name = db.Column(db.String(1000)
Open the init.py file again and import class User from models.py
Open a new python file called auth.py. This file will contain all the logic for our auth routes for example login and signup.
Import the neccesary packages first.
from flask import Blueprint, render_template, redirect, url_for, request, flash
from werkzeug.security import generate_password_hash, check_password_hash
from models import User
from flask_login import login_user, logout_user, login_required
from init import db
Flash is used to show messages to the user for example error messages.
Blueprint is a python package that can help structure a flask application by grouping its functionality into reusable components. Read more about Blueprint package here.
In this file we will put all the auth routes with logic to add new users to the database ,remember the user and logout the user.
Here is the full file below
auth.py
from flask import Blueprint, render_template, redirect, url_for, request, flash
from werkzeug.security import generate_password_hash, check_password_hash
from models import User
from flask_login import login_user, logout_user, login_required
from init import db
auth = Blueprint('auth', __name__)
@auth.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
email = request.form.get('email')
password = request.form.get('password')
remember = True if request.form.get('remember') else False
user = User.query.filter_by(email=email).first()
if not user:
flash('Please sign up first!')
return redirect(url_for('auth.signup'))
elif not check_password_hash(user.password, password):
flash('Please check your login details and try again.')
return redirect(url_for('auth.login'))
login_user(user, remember=remember)
return redirect(url_for('main.profile'))
@auth.route('/signup', methods=['GET', 'POST'])
def signup():
if request.method == 'GET':
return render_template('signup.html')
else:
email = request.form.get('email')
name = request.form.get('name')
password = request.form.get('password')
user = User.query.filter_by(email=email).first()
if user:
flash('Email already exists')
return redirect(url_for('auth.signup'))
new_user = User(email=email, name=name, password=generate_password_hash(password, method='SHA256'))
db.session.add(new_user)
db.session.commit()
return redirect(url_for('auth.login'))
@auth.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('main.index'))
This is the full init.py file.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Qz\k\xec]/'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
from models import User
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# blueprint for auth routes in the app
from auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for non auth routes in the app
from main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
The main.py
file
from flask import Blueprint, render_template
from flask_login import login_required, current_user
from init import create_app, db
main = Blueprint('main', __name__)
@main.route('/')
def index():
return render_template('index.html')
@main.route('/profile')
@login_required
def profile():
return render_template('profile.html', name=current_user.name)
app = create_app()
if __name__ == '__main__':
db.create_all(app=create_app())
app.run(debug=True)
This is the main entry point of the app.
The models.py
file
from flask_login import UserMixin
from init import db
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
name = db.Column(db.String(1000))
def __repr__(self):
return'<User %r>' % self.id
def __init__(self, email, password, name):
db.create_all()
self.email = email
self.password = password
self.name = name
After creating the logic for the app, we now create the templates of the different pages.
Create a templates folder in the main project folder and create a new html file called base.html
This is the main html file from which all the other html file will inherit. We use jinja templates to extend the base.html to the other templates.
Here is the full base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask Login</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
</head>
<body>
<section class="hero is-fullheight" style="background-image:#C4FCEF;">
<div class="hero-head">
<nav class="navbar">
<div class="container">
<div class="navbar-brand">
<a href="{{ url_for('main.index') }}" class="navbar-item" style="color:white">
CampNight
</a>
</div>
<div id="navbarMenuHeroA" class="navbar-menu">
<div class="navbar-end">
<a href="{{ url_for('main.index') }}" class="navbar-item">
Home
</a>
{% if current_user.is_authenticated %}
<a href="{{ url_for('main.profile') }}" class="navbar-item">
Profile
</a>
{% endif %}
{% if not current_user.is_authenticated %}
<a href="{{ url_for('auth.login') }}" class="navbar-item">
Login
</a>
<a href="{{ url_for('auth.signup') }}" class="navbar-item">
Sign Up
</a>
{% endif %}
{% if current_user.is_authenticated %}
<a href="{{ url_for('auth.logout') }}" class="navbar-item">
Logout
</a>
{% endif %}
</div>
</div>
</div>
</nav>
</div>
<div class="hero-body">
<div class="container has-text-centered">
{% block content %}{% endblock %}
</div>
</div>
</section>
</body>
</html>
Notice that for the style we use Bulma css which is a nice framework. Read more about it here.
We then create an index.html
which is the homepage.
index.html
{% extends "base.html" %}
{%block content%}
<h1 class ="title">Welcome to CampNight </h1>
<h2 class="subtitle">Are you ready for an adventure?</h2>
{%endblock%}
Check out the jinja templates used here in curly brackets. You can read more about jinja templates here.
We then create the login.html
template
login.html
{% extends "base.html" %}
{%block content%}
<div class="column is-4 is-offset-4">
<h3 class="title">Login</h3>
<div class="box">
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="notification is-danger">
{{ messages[0] }}
</div>
{% endif %}
{% endwith %}
<form method="POST" action="/login">
<div class="field">
<div class="control">
<input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
</div>
</div>
<div class="field">
<div class="control">
<input class="input is-large" type="password" name="password" placeholder="Your Password">
</div>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox">
Remember me
</label>
</div>
<button class="button is-block is-info is-large is-fullwidth">Login</button>
</form>
</div>
</div>
{%endblock%}
Then the profile.html
to display the name of the particular user once they login.
{% extends 'base.html' %}
{% block content %}
<h1 class="title">
Welcome, {{ name }}!
</h1>
{% endblock %}
We then add the signup.html
for users to sign up.
{% extends "base.html" %}
{% block content %}
<div class="column is-4 is-offset-4">
<h3 class="title">Sign Up</h3>
<div class="box">
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="notification is-danger">
{{ messages[0] }}<br> Go to <a href="{{ url_for('auth.login') }}">login page</a>
</div>
{% endif %}
{% endwith %}
<form method="POST" action="/signup">
<div class="field">
<div class="control">
<input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
</div>
</div>
<div class="field">
<div class="control">
<input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
</div>
</div>
<div class="field">
<div class="control">
<input class="input is-large" type="password" name="password" placeholder="Password">
</div>
</div>
<button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
</form>
</div>
</div>
{% endblock %}
Add another folder in the project folder and name it static.
This folder contains resources for the app such as customised css sheets and images added to the app.
The app is now finally ready and you can run it by running python main.py
in the terminal.
Run the app on local host 5000 and it will displayed in the browser.
Feel free to run the app hosted on here
Resources
Be sure to check out this amazing medium article for more on how to implement user authentification in your web app using flask.
Top comments (3)
well done
would you like to send the github like of the web app ?
Sure.. github.com/RichKitibwa/CampNight