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>