In web applications, user authentication is the foundation for ensuring system security. Simply put, authentication verifies a user’s identity, while permission control determines whether a user has access to specific resources. This article will use the Flask framework and the Session mechanism to implement a simple user login and permission control system from scratch, making it suitable for beginners to understand the core concepts.
I. Preparation: Understanding Sessions and Flask Basics¶
Before starting, let’s familiarize ourselves with two core concepts:
- User Authentication: Verifying a user’s identity through methods like username/password to ensure only legitimate users can access the system.
- Session: A temporary storage area created by the server for each user to maintain state (e.g., login status, user information). Flask’s
sessionobject allows direct interaction with sessions without requiring additional database support.
Environment Setup:
Ensure Flask is installed:
pip install flask
II. Create a Basic Flask Application and Session Configuration¶
First, create a simple Flask application and configure the Session key (required for encrypting session data):
from flask import Flask, render_template, request, session, redirect, url_for, flash
from functools import wraps
app = Flask(__name__)
app.secret_key = 'your_secret_key_here' # Required for encrypting sessions (use a complex random string in production)
III. Implement Login Functionality: Verify Identity and Set Sessions¶
The login function requires two core components: a login form and authentication logic.
1. Login Form (HTML Template)¶
Create templates/login.html with a form for username/password input and error messages:
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>User Login</h1>
<!-- Display error messages (e.g., invalid credentials) -->
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<p style="color: red;">{{ message }}</p>
{% endfor %}
{% endif %}
{% endwith %}
<form method="POST">
<div>
<label>Username:</label>
<input type="text" name="username" required>
</div>
<div>
<label>Password:</label>
<input type="password" name="password" required>
</div>
<button type="submit">Login</button>
</form>
</body>
</html>
2. Handle Login Requests (Verify User and Set Session)¶
Add a login route in app.py to process form submissions and validate users:
# Simulated user database (replace with MySQL/PostgreSQL in production)
USER_DATABASE = {
'admin': 'admin123', # Username-Password pairs
'guest': 'guest456'
}
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
# Validate if the user exists and password is correct
if username in USER_DATABASE and USER_DATABASE[username] == password:
session['username'] = username # Store username in Session
return redirect(url_for('dashboard')) # Redirect to dashboard on success
else:
flash('Invalid username or password') # Show error message via template
# Render login page for GET requests
return render_template('login.html')
IV. Permission Control: Protect Pages Requiring Login¶
Many pages (e.g., personal dashboards, admin panels) require authentication. We’ll use the @login_required decorator to enforce this:
1. Write Login Verification Decorator¶
Add a decorator to check if the user is logged in (exists in Session):
def login_required(f):
@wraps(f) # Preserve original function metadata
def decorated_function(*args, **kwargs):
if 'username' not in session: # Redirect if not logged in
flash('Please log in first')
return redirect(url_for('login'))
return f(*args, **kwargs) # Proceed if logged in
return decorated_function
2. Protect the Personal Dashboard¶
Create a protected dashboard page using the decorator:
@app.route('/dashboard')
@login_required # Only accessible to logged-in users
def dashboard():
return render_template('dashboard.html', username=session['username'])
V. Implement Logout Functionality¶
Logout clears the user’s Session data to invalidate their login state:
@app.route('/logout')
def logout():
session.pop('username', None) # Remove username from Session
flash('You have successfully logged out')
return redirect(url_for('index'))
VI. Improve Pages and Test¶
To enhance user experience, add a homepage and post-logout pages:
1. Homepage Template (templates/index.html)¶
Accessible to unauthenticated users, with login access:
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome to the System</h1>
<a href="{{ url_for('login') }}">Login</a> | <a href="{{ url_for('dashboard') }}">Dashboard</a>
</body>
</html>
2. Dashboard Template (templates/dashboard.html)¶
Visible only to logged-in users, showing their username:
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
</head>
<body>
<h1>Welcome, {{ username }}!</h1>
<a href="{{ url_for('logout') }}">Logout</a>
</body>
</html>
3. Run and Test the Application¶
Start the app:
if __name__ == '__main__':
app.run(debug=True)
Testing Steps:
1. Visit http://127.0.0.1:5000 → Homepage. Click “Dashboard” → Redirected to login.
2. Enter credentials (e.g., admin/admin123 or guest/guest456) → Login success → Dashboard displayed.
3. Click “Logout” → Session cleared → Dashboard access is blocked, redirecting to login.
VII. Summary¶
In this article, we learned:
1. Session Basics: Using Flask’s session to store user state, encrypted with secret_key.
2. User Authentication: Validating credentials via form submission and a hardcoded user database.
3. Permission Control: Using decorators to restrict access to authenticated users.
4. Logout: Clearing Session data to end the user session.
Future Extensions:
- Connect to a database (e.g., MySQL with SQLAlchemy).
- Implement role-based access control (e.g., admin vs. regular users).
- Add password hashing (e.g., using bcrypt instead of plaintext storage).
Flask Sessions provide a straightforward authentication solution for beginners. Once these fundamentals are mastered, you can build more complex web applications.