Flask: User Login and Logout
User login and logout are essential components of secure Flask web applications, enabling authenticated access to protected resources and safe session termination. Built on Flask Authentication, Flask User Registration, Flask Querying the Database, and Flask Relationships in Models, Flask uses extensions like Flask-Login and Flask-Bcrypt to manage user sessions and verify credentials. This tutorial explores Flask user login and logout, covering secure authentication, session management, and route protection, with practical applications in web development.
01. Why Implement User Login and Logout?
Login authenticates users to access personalized features, while logout ensures secure session termination to protect user data. Flask, combined with SQLAlchemy and secure extensions, provides a robust framework for managing user sessions. Leveraging NumPy Array Operations for efficient database queries, Flask supports scalable authentication workflows for applications like blogs, e-commerce platforms, or dashboards.
Example: Basic User Login and Logout
from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///auth.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password_hash, password):
login_user(user)
return "Login successful"
return "Invalid credentials"
@app.route('/logout')
def logout():
logout_user()
return "Logged out"
with app.app_context():
db.create_all()
hashed_password = bcrypt.generate_password_hash('mypassword').decode('utf-8')
db.session.add(User(username='Alice', password_hash=hashed_password))
db.session.commit()
Output:
Login successful (on valid POST request with username='Alice' and password='mypassword')
Logged out (on GET request to /logout)
Explanation:
Flask-Login
- Manages user sessions withlogin_user
andlogout_user
.Flask-Bcrypt
- Verifies passwords against stored hashes.UserMixin
- Provides authentication methods for theUser
model.
02. Key Login and Logout Techniques
Flask offers tools to implement secure and user-friendly login and logout workflows. Below is a summary of key techniques and their applications in web applications:
Technique | Description | Use Case |
---|---|---|
Login Form Handling | Process login credentials | Authenticate users |
Password Verification | Check credentials securely | Ensure valid logins |
Session Management | Maintain user sessions | Track authenticated users |
Logout | Terminate user sessions | Secure session closure |
Protected Routes | Restrict access to authenticated users | Secure dashboards |
2.1 Login Form Handling
Example: Processing Login Form
from flask import Flask, request, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///login.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password_hash, password):
login_user(user)
return "Logged in"
return "Invalid credentials"
return render_template('login.html')
with app.app_context():
db.create_all()
hashed_password = bcrypt.generate_password_hash('testpass').decode('utf-8')
db.session.add(User(username='Bob', password_hash=hashed_password))
db.session.commit()
Output:
Logged in (on valid POST request with username='Bob' and password='testpass')
Explanation:
request.form
- Retrieves username and password from the login form.render_template
- Serves a login form for GET requests.
2.2 Password Verification
Example: Secure Password Check
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///verify.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if not user or not bcrypt.check_password_hash(user.password_hash, password):
return "Invalid username or password"
login_user(user)
return "Login successful"
with app.app_context():
db.create_all()
hashed_password = bcrypt.generate_password_hash('securepass').decode('utf-8')
db.session.add(User(username='Charlie', password_hash=hashed_password))
db.session.commit()
Output:
Login successful (on valid POST request with username='Charlie' and password='securepass')
Explanation:
check_password_hash
- Securely verifies the password against the stored hash.- Generic error message prevents username enumeration attacks.
2.3 Session Management
Example: Managing User Sessions
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, current_user
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///session.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password_hash, password):
login_user(user)
return f"Logged in as {current_user.username}"
return "Invalid credentials"
@app.route('/status')
def status():
if current_user.is_authenticated:
return f"User {current_user.username} is logged in"
return "No user logged in"
with app.app_context():
db.create_all()
hashed_password = bcrypt.generate_password_hash('pass123').decode('utf-8')
db.session.add(User(username='David', password_hash=hashed_password))
db.session.commit()
Output:
Logged in as David (on valid POST request with username='David' and password='pass123')
User David is logged in (on GET request to /status)
Explanation:
current_user
- Tracks the authenticated user across requests.is_authenticated
- Checks if a user is logged in.
2.4 User Logout
Example: Secure Logout
from flask import Flask, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, logout_user, login_required
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///logout.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('home'))
@app.route('/home')
def home():
return "Welcome to the homepage"
with app.app_context():
db.create_all()
Output:
Welcome to the homepage (on GET request to /logout for authenticated user)
Explanation:
logout_user
- Clears the user session.login_required
- Ensures only authenticated users can log out.
2.5 Incorrect Login/Logout Setup
Example: Insecure Login without Hashing
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///insecure.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False) # Plain text
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and user.password == password: # Insecure comparison
return "Logged in"
return "Invalid credentials"
with app.app_context():
db.create_all()
Output:
Logged in (but with insecure password storage)
Explanation:
- Plain-text password storage and comparison are insecure.
- Solution: Use
Flask-Bcrypt
for hashing and verification.
03. Effective Usage
3.1 Recommended Practices
- Use
Flask-Login
for session management andFlask-Bcrypt
for password verification.
Example: Comprehensive Login and Logout
from flask import Flask, request, render_template, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///complete.db'
app.config['SECRET_KEY'] = 'secure-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password_hash, password):
login_user(user)
return redirect(url_for('dashboard'))
return "Invalid credentials"
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('home'))
@app.route('/dashboard')
@login_required
def dashboard():
return f"Welcome, {current_user.username}, to your dashboard"
@app.route('/home')
def home():
return "Welcome to the homepage"
with app.app_context():
db.create_all()
hashed_password = bcrypt.generate_password_hash('secure123').decode('utf-8')
db.session.add(User(username='Eve', password_hash=hashed_password))
db.session.commit()
Output:
Welcome, Eve, to your dashboard (on valid login with username='Eve' and password='secure123')
Welcome to the homepage (after logout)
login_manager.login_view
- Redirects unauthenticated users to the login page.- Combines login, logout, and protected routes for a seamless workflow.
- Uses redirects for better user experience.
3.2 Practices to Avoid
- Avoid insecure password verification or missing session management.
Example: Missing Login Manager
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///wrong.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and user.password == password:
return "Logged in" # No session management
return "Invalid credentials"
with app.app_context():
db.create_all()
Output:
Logged in (but no session tracking)
- Lacks session management and secure password storage.
- Solution: Use
Flask-Login
andFlask-Bcrypt
.
04. Common Use Cases in Web Development
4.1 Secure Blog Access
Authenticate users to access blogging features.
Example: Blog Login
from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password_hash, password):
login_user(user)
return redirect(url_for('dashboard'))
return "Invalid credentials"
@app.route('/dashboard')
@login_required
def dashboard():
return "Blog dashboard"
with app.app_context():
db.create_all()
Output:
Blog dashboard (on valid login)
Explanation:
- Integrates with Flask Relationships in Models to link users to posts.
- Secures access to blogging features.
4.2 E-commerce User Login
Authenticate users to manage orders and profiles.
Example: E-commerce Login
from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///ecommerce.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
orders = db.relationship('Order', backref='customer', lazy=True)
class Order(db.Model):
id = db.Column(db.Integer, primary_key=True)
item = db.Column(db.String(100), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and bcrypt.check_password_hash(user.password_hash, password):
login_user(user)
return redirect(url_for('orders'))
return "Invalid credentials"
@app.route('/orders')
@login_required
def orders():
return "Your orders"
with app.app_context():
db.create_all()
Output:
Your orders (on valid login)
Explanation:
- Links authenticated users to their orders via relationships.
- Secures access to e-commerce features.
Conclusion
Flask user login and logout, powered by Flask-Login, Flask-Bcrypt, and integration with Flask Authentication and NumPy Array Operations, provide a secure and scalable way to manage user sessions. Key takeaways:
- Use
Flask-Login
for session management andFlask-Bcrypt
for password verification. - Protect routes with
login_required
and redirect users appropriately. - Apply login/logout in blogs, e-commerce, or dashboards.
- Avoid insecure practices like plain-text passwords or missing session management.
With these techniques, you can build secure Flask applications that provide seamless and protected user experiences!
Comments
Post a Comment