User Authentication with Python Flask and MySQL

In the following blog, I am going to demonstrate a Login system using Python Flask and MySQL. I’m also covering the basics of Flask and common practices.
Table of content
- Introduction to flask
- Understanding user authentication and why it is important?
- Let’s start
- Creating the main application file
- Adding Routes
- Creating templates
- Connection to the MySQL database
- Adding the Login Method
- Adding Logout Method
- Preventing Direct Navigation
- Output
- Conclusion
Introduction to Flask
If you are thinking of developing a web application in Python, then the first thing that comes into your mind is a framework, and if it is so, then the Flask is the answer to your question.
Flask is light-weight Python framework developed by “Armin Ronacher”. werkzeug WSGI toolkit and jinja2 template engines are the main pillars of the flask framework.
Understanding user authentication and why it is important?
We all undergo the process of authentication initially, whenever we try to navigate to any website or using any mobile Apps, Web applications.
Logins are the set of credentials, which provide the security to prevent unauthorized access to data, and also verify the user’s identity.
Let’s start
Let’s start by installing the necessary packages.
sudo apt install python3-virtualenv
Python3 comes with a venv module to create virtual environments, which are independent groups of Python libraries, one for each project. Packages installed for one project will not influence other projects.
pip3 install flask
The above command will install the Flask module in your project.
pip3 install flask-mysqldb
flask-mysqldb helps you to connect and interact with the MySQL database.
pip install flask-bcrypt
This module is used for password hashing.
Creating the main application file
create an app.py file in your project folder and write the following code.
from flask import Flask, render_template app = Flask(__name__) if __name__ == '__main__': app.run(host='127.0.0.1', port=8000, debug=True)
This code will host our application on 127.0.0.1 which is localhost with port number 8000. By default, the port number is 5000.
If you change to debug mode as True, the server will reload itself on code changes, you no need to restart the server after every change into the code.
Adding Routes
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def root(): return render_template('login.html') @app.route('/home') def home(): return render_template('home.html') if __name__ == '__main__': app.run(host='127.0.0.1', port=8000, debug=True)
here, the (‘/’) route is bound with the login method, so whenever we navigate to that route the login method will render automatically. Same, with the home route.
Creating templates
create templates folder in your project and add all Html files to that folder because Flask will try to find your Html file in this folder.
- Project Folder
- app.py
- templates
- login.html
- home.html
Login.html
<html> <head> {% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} <p style="text-align: center; color: #9C27B0;">{{ message }}</p> {% endfor %} {% endif %} {% endwith %} </head> <body> <div class="main"> <p class="sign" align="center">Login</p> <form class="form1" action="{{url_for('authenticate')}}" method="POST"> <input class="un " type="text" align="center" placeholder="Username" name="username" required> <input class="pass" type="password" align="center" placeholder="Password" name="password" required> <button class="submit" type="submit">Login</button> </form> </div> </body> </html>
Home.html
<!DOCTYPE html> <html lang="en"> <head> <title>Home</title> </head> <body> <form action="{{url_for('logout')}}" > <div class="main"> <h2 style="text-align: center; margin-top: 25px; color: rgb(85, 12, 124); padding-top: 25px;">Welcome {{uname}}</h2> <button class="submit" type="submit" style="margin-top: 25px;">Logout</button> </div> </form> </body> </html>
Full source code for Login.html and Home.html is available on GitHub
Connection to the MySQL database
Add this code to app.py file
from flask_mysqldb import MySQL app = Flask(__name__) app.config['MYSQL_HOST'] ='localhost' app.config['MYSQL_USER'] = 'root' app.config['MYSQL_PASSWORD'] = 'your password' app.config['MYSQL_DB'] = 'name of your database' mysql = MySQL(app)
Adding Authenticate Method
from flask_bcrypt import Bcrypt import os bcrypt = Bcrypt() @app.route('/authentication',methods=['POST','GET']) def authenticate(): if request.method == 'POST': uname = request.form['username'] passwrd = request.form['password'] cur = mysql.connection.cursor() cur.execute("SELECT username,password FROM user WHERE username=%s",[uname]) user = cur.fetchone() temp = user[1] if len(user) > 0: session.pop('username',None) if (bcrypt.check_password_hash(temp,passwrd)) == True: session['username'] = request.form['username'] return render_template('home.html',uname=uname) else: flash('Invalid Username or Password !!') return render_template('login.html') else: return render_template('login.html') if __name__ == '__main__': app.secret_key = os.urandom(24) app.run(host='127.0.0.1', port=8000, debug=True)
The check_password_hash of bcrypt will check the existing password hash against the currently generated password hash , In our case if temp and passwrd will match then it returns True . otherwise returns False.
session.pop() method is used to release a session variable . in our case “username is our session variable . so we will set it to None.
The Session data is stored on top of cookies and the server signs them cryptographically. For this encryption, a Flask application needs a defined SECRET_KEY. app.secret_key = os.urandom(24) will return a 24 character long string of random numbers.
Adding Logout Method
@app.route('/logout') def logout(): session.clear() return render_template('login.html')
Preventing Direct Navigation
In this step, we will restrict a user to access URL to any other pages without login.
For e.g. If any user tries to access localhost:8000/home without login, we can put any error message and the user will remain to the login page.
from flask import Flask , render_template,request,url_for,redirect,session,flash,g @app.before_request def before_request(): g.username = None if 'username' in session: g.username = session['username'] @app.route('/home') def home(): if g.username: return render_template('home.html') else: return render_template('login.html')
Here we will check whether “username” variable is set or not , if the variable is set to session then the user can move to the home page . otherwise user will remain navigate to login page
Here is the final code for app.py file
from flask import Flask,render_template,request,url_for,redirect,session,flash,g from flask_mysqldb import MySQL from flask_bcrypt import Bcrypt import os app = Flask(__name__) app.config['MYSQL_HOST'] ='localhost' app.config['MYSQL_USER'] = 'root' app.config['MYSQL_PASSWORD'] = 'password' app.config['MYSQL_DB'] = 'user' mysql = MySQL(app) bcrypt = Bcrypt() @app.before_request def before_request(): g.username = None if 'username' in session: g.username = session['username'] @app.route('/') def root(): return render_template('login.html') @app.route('/authentication',methods=['POST','GET']) def authenticate(): if request.method == 'POST': uname = request.form['username'] passwrd = request.form['password'] cur = mysql.connection.cursor() cur.execute("SELECT username,password FROM user WHERE username=%s",[uname]) user = cur.fetchone() temp = user[1] if len(user) > 0: session.pop('username',None) if (bcrypt.check_password_hash(temp,passwrd)) == True: session['username'] = request.form['username'] return render_template('home.html',uname=uname) else: flash('Invalid Username or Password !!') return render_template('login.html') else: return render_template('login.html') @app.route('/home') def home(): if g.username: return render_template('home.html') else: return render_template('login.html') @app.route('/logout') def logout(): session.clear() return render_template('login.html') if __name__ == '__main__': app.secret_key = os.urandom(24) app.run(host='127.0.0.1', port=8000, debug=True)
Output
Full source code is available on GitHub
Conclusion
By following this article one can have basic knowledge of flask and also be able to accomplish basic tasks such as authentication for a web app.
I will try to cover more such topics in upcoming blogs