
Blog Project: User Authentication
In this tutorial, we'll add user authentication so users can register, log in, and log out. We'll use Django's built-in authentication system.
Step 1: Create Authentication URLs
Create accounts/urls.py:
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
app_name = 'accounts'
urlpatterns = [
path('register/', views.register, name='register'),
path('login/', auth_views.LoginView.as_view(template_name='accounts/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('profile/', views.profile, name='profile'),
]
Step 2: Configure Authentication Settings
Add to blog_project/settings.py:
# Authentication settings
LOGIN_URL = 'accounts:login'
LOGIN_REDIRECT_URL = 'blog:post_list'
LOGOUT_REDIRECT_URL = 'blog:post_list'
Step 3: Create Registration Form
Create accounts/forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class UserRegisterForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(max_length=30, required=False)
last_name = forms.CharField(max_length=30, required=False)
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name', 'password1', 'password2']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Username'})
self.fields['email'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Email'})
self.fields['first_name'].widget.attrs.update({'class': 'form-control', 'placeholder': 'First Name'})
self.fields['last_name'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Last Name'})
self.fields['password1'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Password'})
self.fields['password2'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Confirm Password'})
Step 4: Create Authentication Views
Create accounts/views.py:
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
user = form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Account created for {username}! You can now log in.')
return redirect('accounts:login')
else:
form = UserRegisterForm()
return render(request, 'accounts/register.html', {'form': form})
@login_required
def profile(request):
user_posts = request.user.blog_posts.all()
return render(request, 'accounts/profile.html', {'user_posts': user_posts})
Step 5: Create Registration Template
Create templates/accounts/register.html:
{% extends 'base.html' %}
{% block title %}Register - My Blog{% endblock %}
{% block content %}
<div class="auth-container">
<div class="auth-card">
<h2>Create an Account</h2>
<p class="auth-subtitle">Join our community and start writing!</p>
<form method="post" class="auth-form">
{% csrf_token %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}">Username</label>
{{ form.username }}
{% if form.username.errors %}
<div class="form-errors">{{ form.username.errors }}</div>
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.email.id_for_label }}">Email</label>
{{ form.email }}
{% if form.email.errors %}
<div class="form-errors">{{ form.email.errors }}</div>
{% endif %}
</div>
<div class="form-row">
<div class="form-group">
<label for="{{ form.first_name.id_for_label }}">First Name</label>
{{ form.first_name }}
</div>
<div class="form-group">
<label for="{{ form.last_name.id_for_label }}">Last Name</label>
{{ form.last_name }}
</div>
</div>
<div class="form-group">
<label for="{{ form.password1.id_for_label }}">Password</label>
{{ form.password1 }}
{% if form.password1.errors %}
<div class="form-errors">{{ form.password1.errors }}</div>
{% endif %}
<small class="form-help">Your password must be at least 8 characters long.</small>
</div>
<div class="form-group">
<label for="{{ form.password2.id_for_label }}">Confirm Password</label>
{{ form.password2 }}
{% if form.password2.errors %}
<div class="form-errors">{{ form.password2.errors }}</div>
{% endif %}
</div>
<button type="submit" class="submit-btn">Register</button>
</form>
<p class="auth-footer">
Already have an account? <a href="{% url 'accounts:login' %}">Log in</a>
</p>
</div>
</div>
{% endblock %}
Step 6: Create Login Template
Create templates/accounts/login.html:
{% extends 'base.html' %}
{% block title %}Login - My Blog{% endblock %}
{% block content %}
<div class="auth-container">
<div class="auth-card">
<h2>Log In</h2>
<p class="auth-subtitle">Welcome back!</p>
<form method="post" class="auth-form">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-error">
Your username and password didn't match. Please try again.
</div>
{% endif %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}">Username</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}">Password</label>
<input type="password" name="password" class="form-control" required>
</div>
<button type="submit" class="submit-btn">Log In</button>
</form>
<p class="auth-footer">
Don't have an account? <a href="{% url 'accounts:register' %}">Register</a>
</p>
</div>
</div>
{% endblock %}
Step 7: Update Base Template
Update templates/base.html to show login/logout links:
<!-- In the navbar section -->
<ul class="nav-menu">
<li><a href="{% url 'blog:post_list' %}">Home</a></li>
<li><a href="#categories">Categories</a></li>
{% if user.is_authenticated %}
<li><a href="{% url 'accounts:profile' %}">Profile</a></li>
<li><a href="{% url 'accounts:logout' %}">Logout</a></li>
{% else %}
<li><a href="{% url 'accounts:login' %}">Login</a></li>
<li><a href="{% url 'accounts:register' %}">Register</a></li>
{% endif %}
</ul>
Step 8: Add Authentication Styles
Add to static/css/style.css:
/* ========================================
Authentication Styles
======================================== */
.auth-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 60vh;
padding: 2rem 0;
}
.auth-card {
background: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: var(--radius);
padding: 2.5rem;
max-width: 500px;
width: 100%;
box-shadow: var(--shadow-md);
}
.auth-card h2 {
margin-bottom: 0.5rem;
color: var(--text-color);
}
.auth-subtitle {
color: var(--text-light);
margin-bottom: 2rem;
}
.auth-form {
margin-bottom: 1.5rem;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.form-help {
display: block;
margin-top: 0.5rem;
font-size: 0.875rem;
color: var(--text-light);
}
.form-errors {
color: #ef4444;
font-size: 0.875rem;
margin-top: 0.5rem;
}
.alert-error {
background-color: #fee2e2;
color: #991b1b;
padding: 1rem;
border-radius: var(--radius);
margin-bottom: 1rem;
}
.auth-footer {
text-align: center;
color: var(--text-light);
}
.auth-footer a {
color: var(--primary-color);
text-decoration: none;
}
.auth-footer a:hover {
text-decoration: underline;
}
Step 9: Protect Views (Optional)
Require login for certain views:
from django.contrib.auth.decorators import login_required
@login_required
def create_post(request):
# Only logged-in users can access this
pass
Testing Authentication
- Visit http://127.0.0.1:8000/accounts/register/
- Create a new account
- Log in with your credentials
- Check that the navbar shows "Profile" and "Logout"
Security Best Practices
Password Requirements
Django automatically enforces: - Minimum length (configurable) - Common password validation - Password strength checks
CSRF Protection
Always use {% csrf_token %} in forms to prevent CSRF attacks.
Session Security
Django handles session security automatically. Configure in settings.py:
SESSION_COOKIE_SECURE = True # HTTPS only (production)
SESSION_COOKIE_HTTPONLY = True # Prevent JavaScript access
What's Next?
Now that users can register and log in, we'll add the final touches: search functionality and deployment instructions.
!!! success "Authentication Complete!" Users can now register and log in. In the next tutorial, we'll add search functionality and prepare for deployment.
Previous Tutorial: JavaScript Interactivity
Next Tutorial: Search & Deployment