Skip to content

第9章:用户认证系统

9.1 Django认证框架

User模型

Django内置了强大的用户认证系统,核心是User模型。User模型包含以下字段:

python
# Django内置User模型的主要字段
class User(models.Model):
    username = models.CharField(max_length=150, unique=True)
    first_name = models.CharField(max_length=150, blank=True)
    last_name = models.CharField(max_length=150, blank=True)
    email = models.EmailField(blank=True)
    is_staff = models.BooleanField(default=False)  # 是否可以访问admin
    is_active = models.BooleanField(default=True)  # 是否激活
    is_superuser = models.BooleanField(default=False)  # 是否是超级用户
    last_login = models.DateTimeField(blank=True, null=True)
    date_joined = models.DateTimeField(default=timezone.now)

使用User模型的基本操作:

python
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login, logout

# 创建用户
user = User.objects.create_user(
    username='john',
    email='john@example.com',
    password='secret'
)

# 创建超级用户
superuser = User.objects.create_superuser(
    username='admin',
    email='admin@example.com',
    password='secret'
)

# 验证用户
user = authenticate(username='john', password='secret')
if user is not None:
    print("用户验证成功")
else:
    print("用户名或密码错误")

# 修改用户属性
user.first_name = 'John'
user.last_name = 'Doe'
user.save()

# 设置密码
user.set_password('newpassword')
user.save()

# 检查密码
if user.check_password('newpassword'):
    print("密码正确")

扩展User模型:

python
# 方法1:一对一关联(推荐)
from django.contrib.auth.models import User
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    avatar = models.ImageField(upload_to='avatars/', blank=True)

# 创建用户配置文件的信号处理器
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.userprofile.save()

# 方法2:自定义User模型
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)

# 在settings.py中设置
AUTH_USER_MODEL = 'myapp.CustomUser'

认证视图

Django提供了内置的认证视图来处理常见的认证任务:

python
# urls.py
from django.urls import path, include
from django.contrib.auth import views as auth_views

urlpatterns = [
    # 使用Django内置认证视图
    path('accounts/', include('django.contrib.auth.urls')),
    
    # 或者单独定义每个视图
    path('login/', auth_views.LoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    path('password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
    path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
    path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
    path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

自定义登录视图:

python
# views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import AuthenticationForm
from django.contrib import messages

def custom_login(request):
    if request.method == 'POST':
        form = AuthenticationForm(request, 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)
                messages.info(request, f"欢迎您,{username}!")
                return redirect('home')
            else:
                messages.error(request, "用户名或密码错误")
        else:
            messages.error(request, "用户名或密码错误")
    else:
        form = AuthenticationForm()
    
    return render(request, 'registration/login.html', {'form': form})

# 自定义登录模板 registration/login.html
"""
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">登录</button>
</form>
"""

权限系统

Django的权限系统基于用户、组和权限的模型:

python
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
from myapp.models import Article

# 创建权限
content_type = ContentType.objects.get_for_model(Article)
permission = Permission.objects.create(
    codename='can_publish_article',
    name='Can Publish Article',
    content_type=content_type,
)

# 为用户分配权限
user = User.objects.get(username='john')
user.user_permissions.add(permission)

# 为组分配权限
group = Group.objects.get(name='Editors')
group.permissions.add(permission)

# 将用户添加到组
user.groups.add(group)

# 检查用户权限
if user.has_perm('myapp.can_publish_article'):
    print("用户有发布文章的权限")

# 检查用户是否属于某个组
if user.groups.filter(name='Editors').exists():
    print("用户是编辑")

# 在视图中检查权限
from django.contrib.auth.decorators import permission_required

@permission_required('myapp.can_publish_article')
def publish_article(request):
    # 只有具有发布权限的用户才能访问
    pass

# 在类视图中检查权限
from django.contrib.auth.mixins import PermissionRequiredMixin

class PublishArticleView(PermissionRequiredMixin, CreateView):
    permission_required = 'myapp.can_publish_article'
    # 视图实现

组管理

组是管理用户权限的有效方式:

python
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType

# 创建组
editors_group = Group.objects.create(name='Editors')
writers_group = Group.objects.create(name='Writers')

# 获取权限
content_type = ContentType.objects.get_for_model(Article)
add_article_perm = Permission.objects.get(
    content_type=content_type,
    codename='add_article'
)
change_article_perm = Permission.objects.get(
    content_type=content_type,
    codename='change_article'
)
delete_article_perm = Permission.objects.get(
    content_type=content_type,
    codename='delete_article'
)

# 为组分配权限
editors_group.permissions.add(
    add_article_perm,
    change_article_perm,
    delete_article_perm
)

# 将用户添加到组
user = User.objects.get(username='john')
user.groups.add(editors_group)

# 检查用户是否属于组
if user.groups.filter(name='Editors').exists():
    print("用户是编辑")

# 从组中移除用户
user.groups.remove(editors_group)

# 删除组
editors_group.delete()

在模板中使用权限:

html
<!-- 检查用户是否已认证 -->
{% if user.is_authenticated %}
    <p>欢迎您,{{ user.username }}!</p>
    <a href="{% url 'logout' %}">退出</a>
{% else %}
    <a href="{% url 'login' %}">登录</a>
{% endif %}

<!-- 检查用户权限 -->
{% if perms.myapp.add_article %}
    <a href="{% url 'article_create' %}">创建文章</a>
{% endif %}

<!-- 检查用户是否属于特定组 -->
{% if user.groups.all %}
    <p>您的组:
    {% for group in user.groups.all %}
        {{ group.name }}{% if not forloop.last %}, {% endif %}
    {% endfor %}
    </p>
{% endif %}

通过Django的认证框架,你可以轻松实现用户注册、登录、权限管理等常见的认证功能。

小结

Django认证框架提供了完整的用户管理系统:

  1. ✅ 内置User模型处理用户基本信息
  2. ✅ 支持扩展User模型以满足特定需求
  3. ✅ 内置认证视图简化登录/登出流程
  4. ✅ 基于权限和组的访问控制
  5. ✅ 模板中的权限检查

掌握认证框架是构建安全Web应用的基础。

下一篇

我们将学习用户注册和登录的具体实现。

9.2 用户注册 →

目录

返回课程目录

Released under the Apache 2.0 License.