django 用户认证系统深度解析

构建一个健壮的 Web 应用,离不开安全的用户认证与精细的权限控制。django 内置了一套强大且灵活的用户认证系统,从基础的登录注册到复杂的对象级权限,几乎能覆盖所有常见需求。本篇教程将带你系统性地掌握 django 用户认证,从核心概念到高阶实践,一步步搭建出可靠的身份管理体系。

1. 认证系统基础

很多开发者容易混淆两个概念:认证(Authentication)授权(Authorization)。简单来说,认证回答“你是谁?”,授权回答“你能做什么?”。django 的认证系统正是围绕这两个核心构建。

django 的认证系统主要由以下部分组成:

  • 用户模型:存储用户信息,默认是 django.contrib.auth.models.User
  • 认证后端:校验用户身份的逻辑,可插拔式替换。
  • 权限与组:控制用户对特定资源的访问。
  • 会话框架:维护用户登录状态。

一个典型的认证流程如下:

  1. 用户提交用户名和密码。
  2. django 调用 authenticate() 方法,该方法逐一尝试配置的所有认证后端。
  3. 后端成功验证后,返回一个用户对象。
  4. 随后调用 login() 将用户 ID 写入会话。

而授权流程则通过 has_perm()has_module_perms() 等方法或模板中的 {% if perms.app_label.codename %} 标签实现,检查用户是否拥有执行特定操作的权限。

2. 自定义用户模型

实际项目中,用手机号或邮箱登录远比用用户名常见。django 推荐从一开始就自定义用户模型,避免后期迁移的巨大成本。

2.1 扩展 AbstractUser

如果只需要在默认用户模型上加几个字段(如头像、手机号),继承 AbstractUser 是最佳选择。

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    phone = models.CharField(max_length=11, unique=True, verbose_name='手机号')
    avatar = models.ImageField(upload_to='avatars/', blank=True, verbose_name='头像')

    class Meta:
        db_table = 'users'

然后在 settings.py 中声明:

AUTH_USER_MODEL = 'myapp.User'

2.2 完全自定义模型

如果希望用邮箱作为唯一标识,完全去掉 username 字段,则需要继承 AbstractBaseUserPermissionsMixin

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('必须提供邮箱地址')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password, **extra_fields)

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    name = models.CharField(max_length=150)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name']

USERNAME_FIELD 指明了认证时使用的字段,REQUIRED_FIELDS 是创建超级用户时必填的额外字段。

3. 认证后端配置

django 的认证后端是可插拔的,你可以同时支持邮箱登录、LDAP 登录或者手机验证码登录。

3.1 自定义认证后端

一个简单的邮箱登录后端:

from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model

User = get_user_model()

class EmailBackend(BaseBackend):
    def authenticate(self, request, email=None, password=None):
        try:
            user = User.objects.get(email=email)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

然后在 settings.py 中注册:

AUTHENTICATION_BACKENDS = [
    'myapp.backends.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',   # 保留默认后端
]

3.2 集成 OAuth2 或 JWT

当开发 API 时,常用 django REST Framework 配合 djangorestframework-simplejwt 实现 JWT 认证。

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

前端通过 /api/token/ 获得 access 和 refresh token,之后在请求头中携带 Authorization: Bearer <token> 即可。

4. 权限与组管理

django 的权限以 app_label.codename 格式存储,比如 blog.add_postblog.change_post。每个模型默认拥有 addchangedeleteview 四种权限。

  • 用户级权限user.user_permissions.add(permission)
  • 组级权限:将权限赋予组,再将用户加入该组,实现批量权限管理。
  • 自定义权限:在模型的 Meta 中声明 permissions
class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()

    class Meta:
        permissions = [
            ('can_publish', '可以发布文章'),
            ('can_archive', '可以归档文章'),
        ]

检查权限时,可以使用 user.has_perm('blog.can_publish')。如果需要对象级权限(比如只能修改自己创建的文章),则需借助第三方库如 django-guardian

5. 安全实践

认证系统的安全不能掉以轻心,以下是几个关键要点:

  • 密码策略:django 默认使用 PBKDF2 算法对密码进行哈希,并支持密码复杂度校验。可以借助 AUTH_PASSWORD_VALIDATORS 配置长度、通用性、数字字母混合等规则。
  • 会话安全:设置 SESSION_COOKIE_AGE 控制过期时间,SESSION_EXPIRE_AT_BROWSER_CLOSE = True 让浏览器关闭即失效,CSRF_COOKIE_HTTPONLY 提高安全性。
  • 账户锁定:通过 django-axes 等插件可以轻松实现登录失败次数限制和账户临时锁定,有效抵御暴力破解。
  • HTTPS 强制:在生产环境中务必开启 SECURE_SSL_REDIRECT 并正确设置 SECURE_HSTS_SECONDS

6. 常见功能实现

日常开发中,有几个认证相关的需求几乎每个项目都会遇到。

6.1 密码重置

django 内置了密码重置视图,只需配置邮件后端:

# urls.py
from django.contrib.auth import views as auth_views

urlpatterns = [
    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'),
]

6.2 注册激活

发送激活邮件,校验用户邮箱的有效性。关键在于生成唯一 token 并设置过期时间。

from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode

uid = urlsafe_base64_encode(str(user.pk).encode())
token = default_token_generator.make_token(user)
link = f'https://example.com/activate/{uid}/{token}'
# 通过邮件发送 link,用户点击后调用 token 校验函数

6.3 “记住我”

实现“记住我”功能只需在登录时延长会话生命周期:

if request.POST.get('remember_me'):
    request.session.set_expiry(1209600)  # 两周
else:
    request.session.set_expiry(0)        # 关闭浏览器即失效

总结

django 的用户认证系统是构建安全应用的基石。从自定义用户模型到细粒度的权限控制,再到防范攻击的安全策略,每一步都值得认真对待。掌握这些内容后,你不仅能快速实现常规的用户管理需求,更能够根据项目特点定制出安全、灵活的认证与授权方案。


📚 推荐阅读:


本文由道满PythonAI团队精心编写,欢迎转发分享,转载请注明出处。