Flask Login Logout using SQLAlchemy with remember me COOKIE_TIME_OUT and password hash
Database Table
CREATE TABLE user (
id INTEGER PRIMARY KEY,
username VARCHAR (64),
email VARCHAR (120),
fullname STRING (255),
password_hash VARCHAR (128),
about_me STRING (140),
last_seen DATETIME
);
#app.py
from flask import Flask, render_template, url_for, request, session, flash, redirect, make_response
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timedelta
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=10)
global COOKIE_TIME_OUT
#COOKIE_TIME_OUT = 60*60*24*7 #7 days
COOKIE_TIME_OUT = 60*5 #5 minutes
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///devdb.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.secret_key = "caircocoders-ednalan-2020"
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
fullname = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return ''.format(self.username)
@app.route('/')
def index():
if 'email' in session:
username_session = session['email']
user_rs = User.query.filter_by(email=username_session).first()
return render_template('index.html', user_rs=user_rs)
else:
return redirect('/login')
@app.route('/login')
def login():
passwordhash = generate_password_hash('test2')
print(passwordhash)
return render_template('login.html')
@app.route('/submit', methods=['POST'])
def login_submit():
_email = request.form['inputEmail']
_password = request.form['inputPassword']
_remember = request.form.getlist('inputRemember')
if 'email' in request.cookies:
username = request.cookies.get('email')
password = request.cookies.get('pwd')
row = User.query.filter_by(email=username).first()
if row and check_password_hash(row.password_hash, password):
#print(username + ' ' + password)
session['email'] = row.email
return redirect('/')
else:
return redirect('/login')
# validate the received values
elif _email and _password:
#check user exists
row = User.query.filter_by(email=_email).first()
if row:
if check_password_hash(row.password_hash, _password):
session['email'] = row.email
if _remember:
resp = make_response(redirect('/'))
resp.set_cookie('email', _email, max_age=COOKIE_TIME_OUT)
resp.set_cookie('pwd', _password, max_age=COOKIE_TIME_OUT)
resp.set_cookie('rem', 'checked', max_age=COOKIE_TIME_OUT)
return resp
return redirect('/')
else:
flash('Invalid Password!')
return redirect('/login')
else:
flash('Invalid Email Or Password!')
return redirect('/login')
else:
flash('Invalid Email Or Password!')
return redirect('/login')
@app.route('/logout')
def logout():
if 'email' in session:
session.pop('email', None)
return redirect('/')
if __name__ == '__main__':
app.run(debug=True)
//templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Home</title>
</head>
<body>
<p align="center"><h1>Python Flask Login Logout</h1></p>
<p align="center"><h1>Hello : {{ user_rs.fullname }}</h1></p>
<p><h3><a href="{{ url_for('logout') }}">Log Out</a></h3></p>
</body>
</html>
//templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Login</title>
<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>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css">
</head>
<body>
<div class="container">
<div class="card card-login mx-auto text-center bg-dark">
<div class="card-header mx-auto bg-dark">
<span> <img src="{{ url_for('static', filename='img/logologin.png') }}" class="w-75" alt="Logo"> </span><br/>
<span class="logo_title mt-5"> Login Dashboard </span>
<div>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger" role="alert">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
</div>
<div class="card-body">
<form method="post" action="/submit">
<div class="input-group form-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-user"></i></span>
</div>
<input type="text" name="inputEmail" class="form-control" value="{% if 'email' in request.cookies %} {{ request.cookies.get('email') }} {% endif %}" placeholder="Email Address">
</div>
<div class="input-group form-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-key"></i></span>
</div>
<input type="password" name="inputPassword" class="form-control" value="{% if 'pwd' in request.cookies %} {{ request.cookies.get('pwd') }} {% endif %}" placeholder="Password">
</div>
<div class="input-group form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" name="inputRemember" checked="{% if 'rem' in request.cookies %} {{ request.cookies.get('rem') }} {% endif %}" autocomplete="off" class="custom-control-input" id="customControlInline">
<label class="custom-control-label" for="customControlInline" style="color:#fff;">Remember me</label>
</div>
</div>
<div class="form-group">
<input type="submit" name="btn" value="Login" class="btn btn-outline-danger float-right login_btn">
</div>
</form>
</div>
</div>
</div>
<style>
body {
background: #17a2b8 !important;
}
.card {
border: 1px solid #28a745;
}
.card-login {
margin-top: 130px;
padding: 18px;
max-width: 30rem;
}
.card-header {
color: #fff;
/*background: #ff0000;*/
font-family: sans-serif;
font-size: 20px;
font-weight: 600 !important;
margin-top: 10px;
border-bottom: 0;
}
.input-group-prepend span{
width: 50px;
background-color: #ff0000;
color: #fff;
border:0 !important;
}
input:focus{
outline: 0 0 0 0 !important;
box-shadow: 0 0 0 0 !important;
}
.login_btn{
width: 130px;
}
.login_btn:hover{
color: #fff;
background-color: #ff0000;
}
.btn-outline-danger {
color: #fff;
font-size: 18px;
background-color: #28a745;
background-image: none;
border-color: #28a745;
}
.form-control {
display: block;
width: 100%;
height: calc(2.25rem + 2px);
padding: 0.375rem 0.75rem;
font-size: 1.2rem;
line-height: 1.6;
color: #28a745;
background-color: transparent;
background-clip: padding-box;
border: 1px solid #28a745;
border-radius: 0;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.input-group-text {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
padding: 0.375rem 0.75rem;
margin-bottom: 0;
font-size: 1.5rem;
font-weight: 700;
line-height: 1.6;
color: #495057;
text-align: center;
white-space: nowrap;
background-color: #e9ecef;
border: 1px solid #ced4da;
border-radius: 0;
}
</style>
</body>
</html>
