使用 Django 內建功能實現使用者註冊與登入

更新日期: 2024 年 12 月 1 日

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 的用法解析

  1. UserCreationForm 的來源與功能
    • 它是 Django 提供的一個表單類,專為使用者註冊設計。
    • 繼承了 ModelForm,直接基於 User 模型生成欄位。
  2. form 的資料流
    • 資料來源request.POST 包含表單提交的數據,這些數據通過 form = UserCreationForm(request.POST) 綁定至表單物件。
    • 驗證form.is_valid() 會檢查必填欄位、密碼一致性等條件。
    • 保存form.save() 會自動將驗證通過的數據保存到資料庫中,創建新的 User 實例。
  3. 保存過程
    • 使用內建的 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 方法詳解

  1. 功能
    • authenticate() 是 Django 的內建方法,用於驗證使用者的憑證(如使用者名與密碼)。
    • 它會檢查資料庫中的使用者,並確認密碼是否正確。
  2. 返回值
    • 驗證成功:返回 User 物件。
    • 驗證失敗:返回 None

login 函數的作用

  1. 功能
    • login() 是 Django 的另一個內建方法,用於在伺服器端為使用者創建 cookie(類似於發號碼牌)。
    • 一旦使用者登入,Django 會在瀏覽器的 cookie 中設置 cookie 資訊。
  2. 撞名問題
    • 我們的函數名稱與 Django 的 login 函數衝突,因此在導入時將其重命名為 login_userfrom django.contrib.auth import login as login_user

登入過程解析

  1. 驗證階段
    • 使用 authenticate() 檢查使用者名與密碼是否有效。
  2. 發號碼牌
    • 使用 login() 為使用者創建 cookie,設置 cookie,表示使用者已登入。
  3. 完整過程
    • 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>

說明

  1. {% if user.is_authenticated %} 的作用
    • 該段模板代碼用來判斷當前使用者是否已通過身份驗證。
    • 如果 user.is_authenticatedTrue,代表使用者已登入,顯示「使用者名」與「登出」選項。
    • 若為 False,則顯示「登入」與「註冊」選項。
  2. 為什麼模板中可以直接取得 user 變數
    • Django 的 RequestContext 預設會將當前請求的使用者變數(request.user)自動添加到模板上下文中。
    • 無需在 views.py 中手動傳入 user,只需啟用 django.template.context_processors.auth(預設啟用)。
  3. is_authenticated 屬性的來源
    • is_authenticatedAbstractBaseUser 類的屬性,表示使用者是否已登入。
    • 它的值與使用者的身份驗證狀態相關,並由 django.contrib.auth 中的中介軟體(Middleware)負責處理。
  4. views.py 的關聯
    • views.py 不直接操作 is_authenticated。它與 Django 的認證中介軟體有關,例如 AuthenticationMiddleware
    • 當使用者登入後,Django 的 cookie 機制會將使用者的認證狀態存儲於伺服器端並更新 request.user

完整的註冊與登入流程

  1. 使用者通過 註冊表單 提交資料,UserCreationForm 進行驗證並加密密碼。
  2. 使用者通過 登入表單 提交憑據,authenticate 驗證身份並使用 login 創建 cookie。
  3. 導覽列根據使用者的登入狀態動態顯示「登入/註冊」或「登出/個人信息」。
  4. 使用者可以隨時點擊「登出」來清除 cookie。

這套流程充分利用了 Django 的內建功能,不僅安全可靠,也非常易於實現和擴展。

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *