Login Register Sytem with Python Flask and Mysql
A complete login and registration system with Python Flask and MySQL
Table account
CREATE TABLE `accounts` (
`id` int(11) NOT NULL,
`fullname` varchar(200) NOT NULL,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#app.py from flask import Flask, request, session, redirect, url_for, render_template from flaskext.mysql import MySQL import pymysql import re app = Flask(__name__) # Change this to your secret key (can be anything, it's for extra protection) app.secret_key = 'cairocoders-ednalan' mysql = MySQL() # MySQL configurations app.config['MYSQL_DATABASE_USER'] = 'root' app.config['MYSQL_DATABASE_PASSWORD'] = '' app.config['MYSQL_DATABASE_DB'] = 'testingdb' app.config['MYSQL_DATABASE_HOST'] = 'localhost' mysql.init_app(app) # http://localhost:5000/pythonlogin/ - this will be the login page @app.route('/pythonlogin/', methods=['GET', 'POST']) def login(): # connect conn = mysql.connect() cursor = conn.cursor(pymysql.cursors.DictCursor) # Output message if something goes wrong... msg = '' # Check if "username" and "password" POST requests exist (user submitted form) if request.method == 'POST' and 'username' in request.form and 'password' in request.form: # Create variables for easy access username = request.form['username'] password = request.form['password'] # Check if account exists using MySQL cursor.execute('SELECT * FROM accounts WHERE username = %s AND password = %s', (username, password)) # Fetch one record and return result account = cursor.fetchone() # If account exists in accounts table in out database if account: # Create session data, we can access this data in other routes session['loggedin'] = True session['id'] = account['id'] session['username'] = account['username'] # Redirect to home page #return 'Logged in successfully!' return redirect(url_for('home')) else: # Account doesnt exist or username/password incorrect msg = 'Incorrect username/password!' return render_template('index.html', msg=msg) # http://localhost:5000/register - this will be the registration page @app.route('/register', methods=['GET', 'POST']) def register(): # connect conn = mysql.connect() cursor = conn.cursor(pymysql.cursors.DictCursor) # Output message if something goes wrong... msg = '' # Check if "username", "password" and "email" POST requests exist (user submitted form) if request.method == 'POST' and 'username' in request.form and 'password' in request.form and 'email' in request.form: # Create variables for easy access fullname = request.form['fullname'] username = request.form['username'] password = request.form['password'] email = request.form['email'] #Check if account exists using MySQL cursor.execute('SELECT * FROM accounts WHERE username = %s', (username)) account = cursor.fetchone() # If account exists show error and validation checks if account: msg = 'Account already exists!' elif not re.match(r'[^@]+@[^@]+\.[^@]+', email): msg = 'Invalid email address!' elif not re.match(r'[A-Za-z0-9]+', username): msg = 'Username must contain only characters and numbers!' elif not username or not password or not email: msg = 'Please fill out the form!' else: # Account doesnt exists and the form data is valid, now insert new account into accounts table cursor.execute('INSERT INTO accounts VALUES (NULL, %s, %s, %s, %s)', (fullname, username, password, email)) conn.commit() msg = 'You have successfully registered!' elif request.method == 'POST': # Form is empty... (no POST data) msg = 'Please fill out the form!' # Show registration form with message (if any) return render_template('register.html', msg=msg) # http://localhost:5000/home - this will be the home page, only accessible for loggedin users @app.route('/') def home(): # Check if user is loggedin if 'loggedin' in session: # User is loggedin show them the home page return render_template('home.html', username=session['username']) # User is not loggedin redirect to login page return redirect(url_for('login')) # http://localhost:5000/logout - this will be the logout page @app.route('/logout') def logout(): # Remove session data, this will log the user out session.pop('loggedin', None) session.pop('id', None) session.pop('username', None) # Redirect to login page return redirect(url_for('login')) # http://localhost:5000/profile - this will be the profile page, only accessible for loggedin users @app.route('/profile') def profile(): # Check if account exists using MySQL conn = mysql.connect() cursor = conn.cursor(pymysql.cursors.DictCursor) # Check if user is loggedin if 'loggedin' in session: # We need all the account info for the user so we can display it on the profile page cursor.execute('SELECT * FROM accounts WHERE id = %s', [session['id']]) account = cursor.fetchone() # Show the profile page with account info return render_template('profile.html', account=account) # User is not loggedin redirect to login page return redirect(url_for('login')) if __name__ == '__main__': app.run(debug=True)
//index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Login</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> </head> <body style="background-color:#ccc;"> <div class="login-box" > <div class="login-header">Login</div> <div class="login-body"> <p>Please enter your username and password</p> <form class="form-group" action="{{ url_for('login') }}" method="post"> <label>Username</label> <input type="text" class="form-control" name="username" placeholder="Username" id="username" required> <label>Password</label> <input type="password" class="form-control" name="password" placeholder="Password" id="password" required> <input type="checkbox" value="checked"><b>Remember</b> <input type="submit" value="Login" class="form-control btn btn-success " name=""> </form> <div id="msg">{{ msg }}</div> <p>No account <a href="{{ url_for('register') }}">Register</a></p> </div> </div> </body> </html>
//home.html {% extends 'layout.html' %} {% block title %}Home{% endblock %} {% block content %} <h1 class="h2">Dashboard</h1> <p>Welcome back, {{ username }}!</p> {% endblock %}
//layout.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> </head> <body class="loggedin"> <nav class="site-header sticky-top py-1"> <div class="container d-flex flex-column flex-md-row justify-content-between"> <a class="py-2" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="d-block mx-auto"><circle cx="12" cy="12" r="10"></circle><line x1="14.31" y1="8" x2="20.05" y2="17.94"></line><line x1="9.69" y1="8" x2="21.17" y2="8"></line><line x1="7.38" y1="12" x2="13.12" y2="2.06"></line><line x1="9.69" y1="16" x2="3.95" y2="6.06"></line><line x1="14.31" y1="16" x2="2.83" y2="16"></line><line x1="16.62" y1="12" x2="10.88" y2="21.94"></line></svg> </a> <a class="py-2 d-none d-md-inline-block" href="{{ url_for('home') }}"><i class="fas fa-home"></i> Home</a> <a class="py-2 d-none d-md-inline-block" href="{{ url_for('profile') }}"><i class="fas fa-user-circle"></i> Profile</a> <a class="py-2 d-none d-md-inline-block" href="{{ url_for('logout') }}"><i class="fas fa-sign-out-alt"></i> Logout</a> </div> </nav> <div class="container-fluid"> <div class="row"> <nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="#"> <i class="fas fa-home"></i> Dashboard <span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <i class="fas fa-shopping-cart"></i> Orders </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <i class="fas fa-shopping-cart"></i> Products </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <i class="fas fa-users"></i> Customers </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <i class="fas fa-download"></i> Reports </a> </li> </ul> </div> </nav> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom"> <div class="col-12"> {% block content %}{% endblock %} </div> </div> </main> </div> </div> </body> </html>
//profile.html {% extends 'layout.html' %} {% block title %}Profile{% endblock %} {% block content %} <h1>Profile Page</h1> <div> <p>Your account details are below:</p> <table> <tr> <td>Name:</td> <td>{{ account['fullname'] }}</td> </tr> <tr> <td>Username:</td> <td>{{ account['username'] }}</td> </tr> <tr> <td>Password:</td> <td>{{ account['password'] }}</td> </tr> <tr> <td>Email:</td> <td>{{ account['email'] }}</td> </tr> </table> </div> {% endblock %}
//register.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Register</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> <link rel="stylesheet" href="../static/css/style.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"> <!-- Google Fonts --> <link href='https://fonts.googleapis.com/css?family=Passion+One' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Oxygen' rel='stylesheet' type='text/css'> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> </head> <body style="background-color:#ccc;"> <div class="container"> <div class="row main"> <div class="main-login main-center"> <h5>Register New user or login existing account</h5> <form action="{{ url_for('register') }}" method="post" autocomplete="off"> <div class="form-group"> <label for="name" class="cols-sm-2 control-label">Your Name</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-user fa" aria-hidden="true"></i></span> <input type="text" class="form-control" name="fullname" id="fullname" placeholder="Enter your Name"/> </div> </div> </div> <div class="form-group"> <label for="email" class="cols-sm-2 control-label">Your Email</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-envelope fa" aria-hidden="true"></i></span> <input type="text" class="form-control" name="email" id="email" placeholder="Enter your Email"/> </div> </div> </div> <div class="form-group"> <label for="username" class="cols-sm-2 control-label">Username</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-users fa" aria-hidden="true"></i></span> <input type="text" class="form-control" name="username" id="username" placeholder="Enter your Username" required> </div> </div> </div> <div class="form-group"> <label for="password" class="cols-sm-2 control-label">Password</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-lock fa-lg" aria-hidden="true"></i></span> <input type="password" class="form-control" name="password" placeholder="Password" id="password" required placeholder="Enter your Password"/> </div> </div> </div> <div class="form-group "> <div id="msg">{{ msg }}</div> <input type="submit" value="Register" class="form-control btn btn-primary " name=""> <p style="padding:5px;"> <a href="{{ url_for('login') }}" class="btn btn-dark ">Login</a></p> </div> </form> </div> </div> </div> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> </body> </html>
//style.css body { background-color: #435165; margin: 0; } .login-box { height: 50%; width: 30%; border: 1px solid grey; margin-left: 35%; margin-top: 10%; position: relative; box-shadow: 21px 12px 24px 10px rgba(0, 0, 0, .5); background: #dadada; } .login-header { text-align: center; font-family: "vardhana",cursive; font-size: 35px; background: linear-gradient(to bottom, #00bfff 0%, #0000ff 100%); color:#fff; position: relative; box-shadow: 1px 3px 14px rgba(0, 0, 0, .5); } .login-body { padding: 20px; line-height: 2; } .msg { color: #721c24; background-color: #f8d7da; border-color: #f5c6cb; padding: .75rem 1.25rem; margin-bottom: 1rem; border: 1px solid transparent; border-radius: .25rem; } .main{ margin-top:50px; } h1.title { font-size: 50px; font-family: 'Passion One', cursive; font-weight: 400; } hr{ width: 10%; color: #fff; } .form-group{ margin-bottom: 15px; } label{ margin-bottom: 15px; } input, input::-webkit-input-placeholder { font-size: 11px; padding-top: 3px; } .main-login{ background-color: #fff; /* shadows and rounded borders */ -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px; -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); } .form-control { height: auto!important; padding: 8px 12px !important; } .input-group { -webkit-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.21)!important; -moz-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.21)!important; box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.21)!important; } .main-center{ margin-top: 30px; margin: 0 auto; max-width: 400px; padding: 10px 40px; background:#009edf; color: #FFF; text-shadow: none; -webkit-box-shadow: 0px 3px 5px 0px rgba(0,0,0,0.31); -moz-box-shadow: 0px 3px 5px 0px rgba(0,0,0,0.31); box-shadow: 0px 3px 5px 0px rgba(0,0,0,0.31); } span.input-group-addon i { color: #fff; font-size: 17px;padding:10px; } .login-button{ margin-top: 5px; } .login-register{ font-size: 11px; text-align: center; } .site-header { background-color: rgba(0, 0, 0, .85); -webkit-backdrop-filter: saturate(180%) blur(20px); backdrop-filter: saturate(180%) blur(20px); } .site-header a { color:#fff; }