文章

Django - 用戶認證

今天我們將學習如何在 Django 中實現用戶認證功能,包括用戶註冊、登入、登出,以及使用者授權。這是任何現代應用程式的核心功能,對於加強應用程式的安全性非常重要。


課程目標

  • 瞭解 Django 預設的用戶認證系統。
  • 實現用戶註冊、登入與登出功能。
  • 在視圖中使用裝飾器進行授權檢查。
  • 自訂用戶模型(如有必要)。

課程內容

1. Django 的用戶認證系統

Django 提供了一個強大的用戶認證框架,支持:

  • 用戶模型(內建的 User 模型)。
  • 登入、登出與密碼管理。
  • 授權與群組權限。

1.1 添加應用

確保 INSTALLED_APPS 包含以下應用:

1
2
3
4
5
6
7
8
INSTALLED_APPS = [
    # 其他應用...
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

1.2 URL 路由配置

確保中間件啟用了 AuthenticationMiddlewareSessionMiddleware

1
2
3
4
5
6
7
8
9
10
MIDDLEWARE = [
    # 其他中間件...
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

2. 用戶註冊

2.1 表單設計

forms.py 中新增用戶註冊表單:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django import forms
from django.contrib.auth.models import User

class UserRegisterForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput, label="密碼")
    confirm_password = forms.CharField(widget=forms.PasswordInput, label="確認密碼")

    class Meta:
        model = User
        fields = ['username', 'email', 'password']

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get("password")
        confirm_password = cleaned_data.get("confirm_password")
        if password != confirm_password:
            raise forms.ValidationError("密碼與確認密碼不一致")

2.2 視圖實作

views.py 中新增註冊功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.contrib.auth.models import User
from django.shortcuts import render, redirect
from .forms import UserRegisterForm

def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.set_password(form.cleaned_data['password'])
            user.save()
            return redirect('login')
    else:
        form = UserRegisterForm()
    return render(request, 'auth/register.html', {'form': form})

2.3 模板設計

templates/auth/register.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
  <head>
    <title>註冊</title>
  </head>
  <body>
    <h1>用戶註冊</h1>
    <form method="post">
      {% csrf_token %} {{ form.as_p }}
      <button type="submit">註冊</button>
    </form>
    <a href="{% url 'login' %}">已有帳戶?點此登入</a>
  </body>
</html>

3. 用戶登入與登出

3.1 登入功能

views.py 中實作登入功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import AuthenticationForm

def user_login(request):
    if request.method == 'POST':
        form = AuthenticationForm(data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                return redirect('post_list')
    else:
        form = AuthenticationForm()
    return render(request, 'auth/login.html', {'form': form})

3.2 登出功能

views.py 中實作登出功能:

1
2
3
4
5
from django.contrib.auth import logout

def user_logout(request):
    logout(request)
    return redirect('login')

3.3 模板設計

templates/auth/login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
  <head>
    <title>登入</title>
  </head>
  <body>
    <h1>用戶登入</h1>
    <form method="post">
      {% csrf_token %} {{ form.as_p }}
      <button type="submit">登入</button>
    </form>
    <a href="{% url 'register' %}">還沒有帳戶?點此註冊</a>
  </body>
</html>

4. 授權與權限控制

4.1 使用裝飾器

在需要授權的視圖中使用 @login_required

1
2
3
4
5
6
from django.contrib.auth.decorators import login_required

@login_required
def post_create(request):
    # 只有登入的用戶才能新增文章
    ...

4.2 自訂權限

對於更細緻的權限管理,可以在模型中設定 permissions

1
2
3
4
5
6
class Post(models.Model):
    ...
    class Meta:
        permissions = [
            ('can_edit_post', 'Can Edit Post'),
        ]

在視圖中檢查權限:

1
2
3
4
5
from django.contrib.auth.decorators import permission_required

@permission_required('app_name.can_edit_post')
def post_update(request, post_id):
    ...

5. URL 配置

urls.py 中新增用戶相關路由:

1
2
3
4
5
6
7
8
from django.urls import path
from . import views

urlpatterns = [
    path('register/', views.register, name='register'),
    path('login/', views.user_login, name='login'),
    path('logout/', views.user_logout, name='logout'),
]

6. 本日總結

  • 實現了用戶註冊、登入與登出功能。
  • 瞭解了授權與權限控制的基本概念。
  • 使用 Django 的內建用戶認證系統快速構建安全的用戶管理功能。

作業

  1. 在 Blog 系統中,限制未登入用戶只能查看文章,無法新增、編輯或刪除文章。
  2. 為用戶新增「用戶頭像」功能,並允許用戶在註冊或個人設定中上傳圖片。
  3. 使用 Django 的群組功能,為不同群組的用戶分配不同的操作權限。

本文章以 CC BY 4.0 授權