django 用户认证系统深度解析
构建一个健壮的 Web 应用,离不开安全的用户认证与精细的权限控制。django 内置了一套强大且灵活的用户认证系统,从基础的登录注册到复杂的对象级权限,几乎能覆盖所有常见需求。本篇教程将带你系统性地掌握 django 用户认证,从核心概念到高阶实践,一步步搭建出可靠的身份管理体系。
1. 认证系统基础
很多开发者容易混淆两个概念:认证(Authentication) 和 授权(Authorization)。简单来说,认证回答“你是谁?”,授权回答“你能做什么?”。django 的认证系统正是围绕这两个核心构建。
django 的认证系统主要由以下部分组成:
- 用户模型:存储用户信息,默认是
django.contrib.auth.models.User。
- 认证后端:校验用户身份的逻辑,可插拔式替换。
- 权限与组:控制用户对特定资源的访问。
- 会话框架:维护用户登录状态。
一个典型的认证流程如下:
- 用户提交用户名和密码。
- django 调用
authenticate() 方法,该方法逐一尝试配置的所有认证后端。
- 后端成功验证后,返回一个用户对象。
- 随后调用
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 字段,则需要继承 AbstractBaseUser 和 PermissionsMixin。
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_post、blog.change_post。每个模型默认拥有 add、change、delete、view 四种权限。
- 用户级权限:
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团队精心编写,欢迎转发分享,转载请注明出处。