Django Authentication 使用者認證系統完全指南 | Django 教學
幾乎所有的 Web 應用程式都需要處理使用者身份驗證。Django 內建了一套功能完善的 Authentication(認證) 系統,從 User 模型 、 登入登出 函數、到 密碼管理 與 密碼重設 流程,全部開箱即用。本篇將帶你全面了解 Django 認證系統的每個環節,並實作一套完整的使用者認證功能。
Django 認證系統概覽
Django 的認證系統由 django.contrib.auth 模組提供,它整合了 認證(Authentication) 與 授權(Authorization) 兩大功能:
- 認證(Authentication):驗證「你是誰」——使用者是否為合法帳號
- 授權(Authorization):決定「你能做什麼」——使用者擁有哪些權限
要使用認證系統,確認 settings.py 中已包含以下設定:
# settings.py
INSTALLED_APPS = [
'django.contrib.auth', # 認證框架核心
'django.contrib.contenttypes', # 權限系統依賴
# ...
]
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware', # Session 支援
'django.contrib.auth.middleware.AuthenticationMiddleware', # 將 user 掛到 request
# ...
]
認證系統的核心元件:
| 元件 | 說明 |
|---|---|
User | 內建使用者模型,提供帳號、密碼、Email 等欄位 |
Permission | Model 層級的權限(add、change、delete、view) |
Group | 權限的集合,可批次指派給使用者 |
Session | 基於 Session 的登入狀態維護機制 |
User 模型欄位
Django 的內建 User 模型(django.contrib.auth.models.User)提供了以下欄位:
| 欄位 | 類型 | 說明 |
|---|---|---|
username | CharField | 使用者名稱(唯一) |
password | CharField | 雜湊後的密碼 |
email | EmailField | 電子郵件 |
first_name | CharField | 名 |
last_name | CharField | 姓 |
is_active | BooleanField | 帳號是否啟用 |
is_staff | BooleanField | 是否可登入 Admin 後台 |
is_superuser | BooleanField | 是否為超級使用者 |
last_login | DateTimeField | 最後登入時間 |
date_joined | DateTimeField | 帳號建立時間 |
常用的方法:
from django.contrib.auth.models import User
# 建立一般使用者
user = User.objects.create_user(
username='alice',
email='alice@example.com',
password='secure_password123' # 自動雜湊處理
)
# 建立超級使用者
admin = User.objects.create_superuser(
username='admin',
email='admin@example.com',
password='admin_password123'
)
# 檢查使用者屬性
user.is_authenticated # True(已登入的使用者永遠為 True)
user.is_anonymous # False
user.get_full_name() # 回傳 "first_name last_name"
user.get_short_name() # 回傳 "first_name"
authenticate / login / logout 函數
Django 提供三個核心函數來處理認證流程,它們位於 django.contrib.auth 模組中。
authenticate()——驗證帳號密碼
from django.contrib.auth import authenticate
# 驗證使用者憑證
user = authenticate(request, username='alice', password='secure_password123')
if user is not None:
# 驗證成功,user 是一個 User 物件
print(f"歡迎,{user.username}!")
else:
# 驗證失敗(帳號不存在或密碼錯誤)
print("帳號或密碼錯誤")
authenticate() 會依序嘗試 settings.py 中 AUTHENTICATION_BACKENDS 列出的所有認證後端,任一成功即回傳 User 物件。
login()——建立登入狀態
from django.contrib.auth import login
# 驗證成功後,建立 Session 登入狀態
login(request, user)
# 此時 Session 中已記錄使用者資訊
# 後續請求的 request.user 會自動指向此使用者
login() 做的事情是:將 User 的 ID 寫入 Session,並在 Response 中設定 sessionid Cookie,後續請求就能透過 Cookie 識別使用者身份。
logout()——登出
from django.contrib.auth import logout
# 清除 Session,登出使用者
logout(request)
# 此時 request.user 會變成 AnonymousUser
完整登入 View 範例
# views.py
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import render, redirect
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
# 第一步:驗證帳號密碼
user = authenticate(request, username=username, password=password)
if user is not None:
# 第二步:建立登入狀態
login(request, user)
# 第三步:重導向到原始頁面或首頁
next_url = request.GET.get('next', '/')
return redirect(next_url)
else:
return render(request, 'accounts/login.html', {
'error': '帳號或密碼錯誤'
})
return render(request, 'accounts/login.html')
def logout_view(request):
if request.method == 'POST':
logout(request)
return redirect('login')
return redirect('/')
@login_required 裝飾器
@login_required 是最常用的認證裝飾器,它會在 View 執行前自動檢查使用者是否已登入。未登入的使用者會被重導向到登入頁面。
from django.contrib.auth.decorators import login_required
@login_required
def dashboard(request):
"""只有已登入的使用者才能存取此頁面"""
return render(request, 'accounts/dashboard.html', {
'user': request.user
})
# 自訂登入頁面 URL
@login_required(login_url='/custom-login/')
def profile(request):
return render(request, 'accounts/profile.html')
重導向行為:
- 未登入使用者造訪
/dashboard/ - 被重導向到
LOGIN_URL(預設/accounts/login/),URL 帶有?next=/dashboard/ - 使用者登入成功後,自動跳回
/dashboard/
在 settings.py 中設定相關的重導向 URL:
# settings.py
LOGIN_URL = '/accounts/login/' # 未登入時重導向的目標
LOGIN_REDIRECT_URL = '/dashboard/' # 登入成功後的預設重導向
LOGOUT_REDIRECT_URL = '/' # 登出後的重導向目標
在 CBV 中使用 LoginRequiredMixin
如果你使用 Class-Based Views(CBV) ,可以使用 LoginRequiredMixin:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class DashboardView(LoginRequiredMixin, TemplateView):
template_name = 'accounts/dashboard.html'
login_url = '/accounts/login/' # 可選,預設使用 settings.LOGIN_URL
注意:LoginRequiredMixin 必須放在 第一個 繼承位置,才能正確攔截未登入的請求。
LoginView / LogoutView CBV
Django 提供了內建的 LoginView 和 LogoutView ,讓你不用自己寫認證邏輯,只需要設定 URL 和模板即可。
LoginView
# urls.py
from django.contrib.auth.views import LoginView
urlpatterns = [
path('accounts/login/', LoginView.as_view(
template_name='accounts/login.html', # 自訂模板
redirect_authenticated_user=True, # 已登入使用者自動跳轉
), name='login'),
]
對應的模板只需要提供一個 form:
{# templates/accounts/login.html #}
<h2>登入</h2>
{% if form.errors %}
<p style="color: red;">帳號或密碼錯誤,請重試。</p>
{% endif %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">登入</button>
</form>
LogoutView
# urls.py
from django.contrib.auth.views import LogoutView
urlpatterns = [
path('accounts/logout/', LogoutView.as_view(
next_page='/', # 登出後重導向到首頁
), name='logout'),
]
{# 在模板中使用 POST 請求登出 #}
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button type="submit">登出</button>
</form>
Django 4.1 以後,LogoutView 預設只接受 POST 請求,不再支援 GET 登出,這是為了防止 CSRF 攻擊(跨站請求偽造) 。
密碼管理
Django 提供了完善的密碼管理機制,包括密碼的設定、驗證與雜湊處理。
set_password() 與 check_password()
from django.contrib.auth.models import User
user = User.objects.get(username='alice')
# 設定新密碼(自動雜湊,不是存明碼)
user.set_password('new_secure_password')
user.save() # 記得要呼叫 save()
# 驗證密碼是否正確
user.check_password('new_secure_password') # True
user.check_password('wrong_password') # False
重要提醒:永遠不要直接賦值 user.password = '...',這樣會存入明碼。必須使用 set_password() 方法,它會自動進行雜湊處理。
密碼雜湊機制
Django 使用 PBKDF2 演算法作為預設的密碼雜湊方式,儲存格式為 <algorithm>$<iterations>$<salt>$<hash>:
pbkdf2_sha256$600000$randomsalt$hashed_value_here
你可以在 settings.py 中自訂使用的雜湊演算法:
# settings.py
PASSWORD_HASHERS = [
# 第一個為新密碼的預設演算法
'django.contrib.auth.hashers.PBKDF2PasswordHasher', # 預設
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher', # 推薦(需 pip install argon2-cffi)
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', # 需 pip install bcrypt
]
密碼驗證器
Django 內建四個密碼驗證器,確保使用者設定的密碼符合安全標準:
# settings.py
AUTH_PASSWORD_VALIDATORS = [
{
# 密碼不能與使用者屬性(username、email 等)太相似
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
# 密碼最短長度
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {'min_length': 8},
},
{
# 密碼不能是常見弱密碼(內建 20,000 組常見密碼清單)
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
# 密碼不能全部是數字
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
密碼重設流程
Django 內建完整的密碼重設(Password Reset)流程,由四個 View 組成。你只需設定 URL 與模板,無需自己處理 token 產生與驗證邏輯。
設定四個 URL
# urls.py
from django.contrib.auth import views as auth_views
urlpatterns = [
# 第一步:輸入 Email 頁面
path('password-reset/', auth_views.PasswordResetView.as_view(
template_name='accounts/password_reset.html',
email_template_name='accounts/password_reset_email.html',
subject_template_name='accounts/password_reset_subject.txt',
success_url='/password-reset/done/',
), name='password_reset'),
# 第二步:Email 已寄出的提示頁面
path('password-reset/done/', auth_views.PasswordResetDoneView.as_view(
template_name='accounts/password_reset_done.html',
), name='password_reset_done'),
# 第三步:點擊連結後的重設表單頁面
path('password-reset-confirm/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(
template_name='accounts/password_reset_confirm.html',
success_url='/password-reset-complete/',
), name='password_reset_confirm'),
# 第四步:重設完成的提示頁面
path('password-reset-complete/', auth_views.PasswordResetCompleteView.as_view(
template_name='accounts/password_reset_complete.html',
), name='password_reset_complete'),
]
對應模板
{# templates/accounts/password_reset.html #}
<h2>重設密碼</h2>
<p>請輸入您的 Email,我們將寄送密碼重設連結。</p>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">寄送重設連結</button>
</form>
{# templates/accounts/password_reset_email.html(Email 內容模板)#}
您好 {{ user.get_username }},
請點擊以下連結重設您的密碼:
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
此連結僅可使用一次,若您未要求重設密碼,請忽略此信件。
{# templates/accounts/password_reset_confirm.html #}
<h2>設定新密碼</h2>
{% if validlink %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">確認新密碼</button>
</form>
{% else %}
<p>此重設連結已失效,請重新申請。</p>
{% endif %}
註冊功能實作
Django 沒有提供內建的註冊 View,但提供了 UserCreationForm 表單類別,讓你快速實作使用者註冊功能。
使用 UserCreationForm
# views.py
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login
from django.shortcuts import render, redirect
def register_view(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
# 儲存新使用者
user = form.save()
# 註冊成功後自動登入
login(request, user)
return redirect('dashboard')
else:
form = UserCreationForm()
return render(request, 'accounts/register.html', {'form': form})
擴展 UserCreationForm 加入 Email 欄位
預設的 UserCreationForm 只有 username 和 password 欄位。若需要 Email 欄位,可以繼承並擴展:
# forms.py
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(
required=True,
help_text='請輸入有效的電子郵件地址'
)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
def clean_email(self):
"""檢查 Email 是否已被使用"""
email = self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise forms.ValidationError('此 Email 已被註冊')
return email
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
# views.py
from .forms import CustomUserCreationForm
def register_view(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect('dashboard')
else:
form = CustomUserCreationForm()
return render(request, 'accounts/register.html', {'form': form})
對應的模板:
{# templates/accounts/register.html #}
<h2>建立帳號</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">註冊</button>
</form>
<p>已有帳號?<a href="{% url 'login' %}">前往登入</a></p>
Session 安全性設定
認證系統依賴 Session 維護登入狀態,確保 Session 的安全性非常重要:
# settings.py
SESSION_COOKIE_HTTPONLY = True # 防止 JavaScript 讀取 Cookie
SESSION_COOKIE_SECURE = True # 只透過 HTTPS 傳送(生產環境)
SESSION_COOKIE_SAMESITE = 'Lax' # 防止 CSRF 攻擊
SESSION_COOKIE_AGE = 1209600 # Session 有效期 14 天(單位:秒)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 關閉瀏覽器後 Session 不失效
總結
Django 的 Authentication 系統功能完善且開箱即用,大幅降低了實作使用者認證的工作量。以下整理本篇的核心要點:
- 認證系統架構 整合了 User 模型、Permission、Group 與 Session,提供從登入到權限控制的完整解決方案
- authenticate / login / logout 三個核心函數各司其職——驗證憑證、建立登入狀態、清除 Session
- @login_required 裝飾器與 LoginRequiredMixin 讓存取控制變得簡單,搭配
LOGIN_URL設定可自訂重導向行為 - LoginView / LogoutView 是 Django 內建的認證 CBV,只需設定模板和 URL 就能快速上線
- 密碼管理 透過
set_password和check_password處理,Django 自動進行雜湊,永遠不存明碼 - 密碼重設流程 由四個內建 View 組成,包含 token 產生與驗證,只需撰寫模板即可使用
- 註冊功能 透過
UserCreationForm快速實作,可繼承擴展以加入自訂欄位
掌握了認證系統後,下一篇我們將深入探討 自訂使用者模型(Custom User Model) ,學習如何透過 AbstractUser 和 AbstractBaseUser 打造符合業務需求的使用者模型。