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

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')

 

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

References

https://speckyboy.com/login-pages-html5-css/

https://www.maartenbaert.be/simplescreenrecorder/

Read More
Zeel Pandya Zeel Pandya June 16, 2020 0 Comments