In the previous part of this series, we saw how to get started with Python Flask and MySQL and implemented the user registration portion of our application. In this tutorial, we'll take this to the next level by implementing the sign-in and logout functionality for our application.
Getting Started
First clone the source code of the previous tutorial from GitHub.
git clone https://github.com/jay3dec/PythonFlaskMySQLApp---Part-1.git
Once the source code has been cloned, navigate to the PythonFlaskMySQLApp---Part-1
directory and start the server.
python app.py
Point your browser to http://localhost:5002 and you should have the application running.
Creating the Sign-In Interface
Navigate to PythonFlaskMySQLApp---Part-1/templates
and create a new file called signin.html
. Open signin.html
and add the following HTML code:
<!DOCTYPE html> <html lang="en"> <head> <title>Python Flask Bucket List App</title> <link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet"> <link href="../static/css/signup.css" rel="stylesheet"> <script src="../static/js/jquery-1.11.2.js"></script> </head> <body> <div class="container"> <div class="header"> <nav> <ul class="nav nav-pills pull-right"> <li role="presentation" ><a href="/">Home</a></li> <li role="presentation" class="active"><a href="#">Sign In</a></li> <li role="presentation" ><a href="/showSignUp">Sign Up</a></li> </ul> </nav> <h3 class="text-muted">Python Flask App</h3> </div> <div class="jumbotron"> <h1>Bucket List App</h1> <form class="form-signin" action="/validateLogin" method="post"> <label for="inputEmail" class="sr-only">Email address</label> <input type="email" name="inputEmail" id="inputEmail" class="form-control" placeholder="Email address" required autofocus> <label for="inputPassword" class="sr-only">Password</label> <input type="password" name="inputPassword" id="inputPassword" class="form-control" placeholder="Password" required> <button id="btnSignIn" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> </form> </div> <footer class="footer"> <p>© Company 2015</p> </footer> </div> </body> </html>
Open app.py
and add a new route for the sign-in interface.
@app.route('/showSignin') def showSignin(): return render_template('signin.html')
Next, open up index.html
and signup.html
, and add the href
link for sign-in on both the pages as /showSignin
. Save all the changes and restart the server.
python app.py
Point your browser to http://localhost:5002 and click on the Sign In link, and you should be able to see the sign-in page.
Implementing Sign-In
Now, we need to create function to validate the user login. On clicking Sign In we'll post the entered email address and password to the validate user function.
Creating a Stored Procedure
To validate a user, we'll need a MySQL stored procedure. So create a MySQL stored procedure as shown:
DELIMITER $$ CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_validateLogin`( IN p_username VARCHAR(20) ) BEGIN select * from tbl_user where user_username = p_username; END$$ DELIMITER ;
We'll get the user details based on the username
from the MySQL database using sp_validateLogin
. Once we have the hashed password we'll validate it against the password entered by the user.
Validate the User Method
Create a method to validate the user which we'll call when the user submits the form:
@app.route('/validateLogin',methods=['POST']) def validateLogin(): try: _username = request.form['inputEmail'] _password = request.form['inputPassword'] except Exception as e: return render_template('error.html',error = str(e))
As seen in the above code, we have read the posted email address and password into _username
and _password
. Now we'll call the sp_validateLogin
procedure with the parameter _username
. So create a MySQL connection inside the validateLogin
method:
con = mysql.connect()
Once the connection has been created, create a cursor
using the con
connection.
cursor = con.cursor()
Using the cursor, call the MySQL stored procedure as shown:
cursor.callproc('sp_validateLogin',(_username,))
Get the fetched records from the cursor as shown:
data = cursor.fetchall()
If the data has some records, we'll match the retrieved password against the password entered by the user.
if len(data) > 0: if check_password_hash(str(data[0][3]),_password): return redirect('/userHome') else: return render_template('error.html',error = 'Wrong Email address or Password.') else: return render_template('error.html',error = 'Wrong Email address or Password.')
As seen in the above code, we have used a method called check_password_hash
to check if the returned hash password matches the password entered by the user. If all is good then we'll redirect the user to userHome.html
. And if there is any error, we'll display error.html
with the error message.
Here is the complete validateLogin
code:
@app.route('/validateLogin',methods=['POST']) def validateLogin(): try: _username = request.form['inputEmail'] _password = request.form['inputPassword'] # connect to mysql con = mysql.connect() cursor = con.cursor() cursor.callproc('sp_validateLogin',(_username,)) data = cursor.fetchall() if len(data) > 0: if check_password_hash(str(data[0][3]),_password): session['user'] = data[0][0] return redirect('/userHome') else: return render_template('error.html',error = 'Wrong Email address or Password.') else: return render_template('error.html',error = 'Wrong Email address or Password.') except Exception as e: return render_template('error.html',error = str(e)) finally: cursor.close() con.close()
Create a page called userHome.html
inside the templates folder and add the following HTML code:
<!DOCTYPE html> <html lang="en"> <head> <title>Python Flask Bucket List App</title> <link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet"> <link href="../static/css/signup.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="header"> <nav> <ul class="nav nav-pills pull-right"> <li role="presentation" class="active"><a href="/logout">Logout</a> </li> </ul> </nav> <h3 class="text-muted">Python Flask App</h3> </div> <div class="jumbotron"> <h1>Welcome Home !!</h1> </div> <footer class="footer"> <p>© Company 2015</p> </footer> </div> </body> </html>
Also create an error page called error.html
in templates
folder and add the following HTML code:
<!DOCTYPE html> <html lang="en"> <head> <title>Unauthorized Access:: Python Flask Bucket List App</title> <link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="header"> <nav> <ul class="nav nav-pills pull-right"> <li role="presentation" class="active"><a href="#">Home</a> </li> <li role="presentation"><a href="/showSignin">Sign In</a> </li> <li role="presentation"><a href="/showSignUp">Sign Up</a> </li> </ul> </nav> <h3 class="text-muted">Python Flask App</h3> </div> <div class="jumbotron"> <h1>{{error}}</h1> </div> <footer class="footer"> <p>© Company 2015</p> </footer> </div> </body> </html>
Inside error.html
we have an element as shown:
<h1>{{error}}</h1>
The value for the variable can be passed from the render_template
function and can be set dynamically.
On successful sign-in we are redirecting the user to the user home page, so we need to create a route called /userHome
as shown:
@app.route('/userHome') def userHome(): return render_template('userHome.html')
Save all the changes and restart the server. Click on the Sign In link in the home page and try to sign in using a valid email address and password. On successful user validation, you should have a page as shown below:
On an unsuccessful user validation the user will be redirected to an error page as shown below:
Here we have used a separate error page to display the error. It's also fine if you want to use the same page to display the error message.
Restricting Unauthorized Access to the User Home Page
On successful user validation a user is redirected to the user home page. But right now even an unauthorized user can view the home page by simply browsing the URL http://localhost:5002/userHome.
To restrict unauthorized user access, we'll check for a session variable which we'll set on successful user login. So import session
from flask:
from flask import session
We also need to set a secret key for the session. So in app.py
, after the app as been initialized, set the secret key as shown :
app.secret_key = 'why would I tell you my secret key?'
Now, inside the validateLogin
method, before redirecting the user to /userHome
on successful sign-in, set the session
variable as shown:
session['user'] = data[0][0]
Next, inside the userHome
method, check for the session variable before rendering userHome.html
. If the session variable is not found, redirect to the error page.
@app.route('/userHome') def userHome(): if session.get('user'): return render_template('userHome.html') else: return render_template('error.html',error = 'Unauthorized Access')
Save all the changes and restart the server. Without signing in, try to navigate to http://localhost:5002/userHome and since you haven't logged in yet, you should be redirected to the error page.
Implementing Logout
Implementing the logout functionality is the simplest. All we need to do is make the session variable user
null and redirect the user to the main page.
Inside app.py
, create a new route and method for logout
as shown:
@app.route('/logout') def logout(): session.pop('user',None) return redirect('/')
We have already set the href for the log out button to /logout
. So save all the changes and restart the server. From the home page, click on Sign In and try to log in using a valid email address and password. Once signed in, click on the Logout button in user home and you should be successfully logged out from the application.
Conclusion
In this part of the tutorial, we saw how to implement the user login and logout functionality. We also saw how to restrict unauthorized access to application pages. In the next part of this tutorial, we'll implement the functionality for the logged-in user to add and edit a blog post in the application.
Source code from this tutorial is available on GitHub.
Do let us know your thoughts in the comments below!
Comments