使用 Django 內建功能實現使用者註冊與登入
更新日期: 2024 年 12 月 1 日
本文為 Django 會員系統建立教學,第 3 篇:
- 設計登入與註冊功能的基礎路由與頁面配置
- Django 使用者密碼加密方式詳解
- 使用 Django 內建功能實現使用者註冊與登入 👈 所在位置
- 使用 Django 實現安全登出功能:完整指南
- Django 使用者登入與資料操作的最佳實踐
- Django: 添加公開留言與履歷列表功能
- 使用 Alpine.js 和 Django 動態管理留言按鈕啟用狀態
- Django 收藏功能的實現:使用 ManyToMany 關係與自定義中介模型
建議閱讀本文前,先閱讀完 Django 與前端框架教學 系列文
Django 提供了一套強大的認證與使用者管理功能,可以輕鬆實現安全的使用者註冊、登入。
本文將詳細介紹如何使用 Django 的內建功能搭建基礎使用者系統。
使用內建的 UserCreationForm
進行註冊
Django 提供了一個方便的 UserCreationForm
類,它基於 ModelForm,幫助我們快速處理使用者註冊表單,包括表單驗證和密碼加密。
註冊視圖(register
)
在 user/views.py
中新增註冊功能:
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
def register(request):
if request.method == "POST":
form = UserCreationForm(request.POST) # 將表單與 POST 數據綁定
if form.is_valid(): # 驗證表單數據
form.save() # 保存使用者資料
messages.success(request, "註冊成功!")
return redirect("pages:home") # 重定向至首頁
else:
form = UserCreationForm() # 創建空白表單
return render(request, "users/register.html", {"form": form})
UserCreationForm
的用法解析
UserCreationForm
的來源與功能:- 它是 Django 提供的一個表單類,專為使用者註冊設計。
- 繼承了
ModelForm
,直接基於User
模型生成欄位。
form
的資料流:- 資料來源:
request.POST
包含表單提交的數據,這些數據通過form = UserCreationForm(request.POST)
綁定至表單物件。 - 驗證:
form.is_valid()
會檢查必填欄位、密碼一致性等條件。 - 保存:
form.save()
會自動將驗證通過的數據保存到資料庫中,創建新的User
實例。
- 資料來源:
- 保存過程:
- 使用內建的
UserManager.create_user()
方法,將密碼加密後儲存,確保安全性。
- 使用內建的
註冊模板(register.html
)
在 users/templates/users/register.html
中設計註冊表單:
{% extends "shared/layout.html" %}
{% block "content" %}
<h1 class="text-3xl">註冊</h1>
<form method="POST" class="flex flex-col gap-2">
{% csrf_token %}
<div class="form-control">
<label>Username</label>
<input type="text" class="w-full max-w-xs input input-bordered" name="username" />
</div>
<div class="form-control">
<label>Email</label>
<input type="email" class="w-full max-w-xs input input-bordered" name="email" />
</div>
<div class="form-control">
<label>Password</label>
<input type="password" class="w-full max-w-xs input input-bordered" name="password1" />
</div>
<div class="form-control">
<label>Password 確認</label>
<input type="password" class="w-full max-w-xs input input-bordered" name="password2" />
</div>
<div>
<button class="btn btn-primary">註冊</button>
</div>
</form>
{% endblock %}
表單輸入欄位的設計依據
此表單的欄位是根據 Django 提供的 UserCreationForm
類推敲出來的,其欄位對應如下:
username
: 對應UserCreationForm
中的username
欄位,為使用者名的輸入框。email
: 雖然UserCreationForm
預設不包含電子郵件欄位,但可自訂擴展,此處用於記錄使用者的電子郵件地址。password1
: 對應UserCreationForm
的第一個密碼輸入欄位,用於輸入密碼。password2
: 對應UserCreationForm
的第二個密碼輸入欄位,用於確認密碼。
UserCreationForm
是基於 Django 的 User
模型,它預設包含了使用者名與密碼相關的欄位,並自動檢查兩次密碼是否一致。
使用內建的 authenticate
進行登入驗證
Django 的 authenticate
方法用於驗證使用者的憑據。
驗證成功後,我們還需要使用 login
函數為使用者創建 cookie(類似分發號碼牌)。
登入視圖(login
)
在 user/views.py
中實現登入功能:
from django.contrib.auth import authenticate, login as login_user
from django.contrib import messages
from django.shortcuts import render, redirect
def login(request):
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(request, username=username, password=password) # 驗證使用者
if user is not None:
login_user(request, user) # 為使用者創建 cookie
messages.success(request, "登入成功!")
return redirect("pages:home")
else:
messages.error(request, "登入失敗,請檢查您的使用者名與密碼。")
return render(request, "users/login.html")
authenticate
方法詳解
- 功能:
authenticate()
是 Django 的內建方法,用於驗證使用者的憑證(如使用者名與密碼)。- 它會檢查資料庫中的使用者,並確認密碼是否正確。
- 返回值:
- 驗證成功:返回
User
物件。 - 驗證失敗:返回
None
。
- 驗證成功:返回
login
函數的作用
- 功能:
login()
是 Django 的另一個內建方法,用於在伺服器端為使用者創建 cookie(類似於發號碼牌)。- 一旦使用者登入,Django 會在瀏覽器的 cookie 中設置 cookie 資訊。
- 撞名問題:
- 我們的函數名稱與 Django 的
login
函數衝突,因此在導入時將其重命名為login_user
:from django.contrib.auth import login as login_user
。
- 我們的函數名稱與 Django 的
登入過程解析
- 驗證階段:
- 使用
authenticate()
檢查使用者名與密碼是否有效。
- 使用
- 發號碼牌:
- 使用
login()
為使用者創建 cookie,設置 cookie,表示使用者已登入。
- 使用
- 完整過程:
- 無
login()
:即使驗證成功,使用者依然未登入,因為未建立 cookie。
- 無
登入模板(login.html
)
在 templates/users/login.html
中設計登入表單:
{% extends "shared/layout.html" %}
{% block "content" %}
<h1 class="text-3xl">登入</h1>
<form method="POST" class="flex flex-col gap-2">
{% csrf_token %}
<div class="form-control">
<label>Username</label>
<input type="text" class="w-full max-w-xs input input-bordered" name="username" />
</div>
<div class="form-control">
<label>Password</label>
<input type="password" class="w-full max-w-xs input input-bordered" name="password" />
</div>
<div>
<button class="btn btn-primary">登入</button>
</div>
</form>
{% endblock %}
在導覽列中動態顯示登入狀態
修改 templates/shared/navbar.html
,根據使用者的登入狀態顯示不同選項:
<div class="navbar bg-neutral text-neutral-content">
<div class="flex-1">
<a href="{% url 'pages:home' %}" class="text-xl btn btn-ghost">PyDev</a>
</div>
<div class="flex-none">
<ul class="px-1 menu menu-horizontal">
{% if user.is_authenticated %}
<li><a>{{ user.username }}</a></li>
<li><a href="{% url 'users:logout' %}">登出</a></li>
{% else %}
<li><a href="{% url 'users:login' %}">登入</a></li>
<li><a href="{% url 'users:register' %}">註冊</a></li>
{% endif %}
</ul>
</div>
</div>
說明
{% if user.is_authenticated %}
的作用:- 該段模板代碼用來判斷當前使用者是否已通過身份驗證。
- 如果
user.is_authenticated
為True
,代表使用者已登入,顯示「使用者名」與「登出」選項。 - 若為
False
,則顯示「登入」與「註冊」選項。
- 為什麼模板中可以直接取得
user
變數:- Django 的
RequestContext
預設會將當前請求的使用者變數(request.user
)自動添加到模板上下文中。 - 無需在
views.py
中手動傳入user
,只需啟用django.template.context_processors.auth
(預設啟用)。
- Django 的
is_authenticated
屬性的來源:is_authenticated
是AbstractBaseUser
類的屬性,表示使用者是否已登入。- 它的值與使用者的身份驗證狀態相關,並由
django.contrib.auth
中的中介軟體(Middleware)負責處理。
- 與
views.py
的關聯:views.py
不直接操作is_authenticated
。它與 Django 的認證中介軟體有關,例如AuthenticationMiddleware
。- 當使用者登入後,Django 的 cookie 機制會將使用者的認證狀態存儲於伺服器端並更新
request.user
。
完整的註冊與登入流程
- 使用者通過 註冊表單 提交資料,
UserCreationForm
進行驗證並加密密碼。 - 使用者通過 登入表單 提交憑據,
authenticate
驗證身份並使用login
創建 cookie。 - 導覽列根據使用者的登入狀態動態顯示「登入/註冊」或「登出/個人信息」。
- 使用者可以隨時點擊「登出」來清除 cookie。
這套流程充分利用了 Django 的內建功能,不僅安全可靠,也非常易於實現和擴展。