第六章:Django 用户认证与授权详解 在任何 Web 应用程序中,用户认证与授权都是保障系统安全的核心机制。用户认证(Authentication) 用于验证用户身份,确认“你是谁”;用户授权(Authorization) 则在认证通过后,决定用户“能做什么”——即对资源访问、数据操作及功能使用的精细化控制。Django 内置成熟、可扩展且符合安全最佳实践的认证与授权框架,覆盖从基础登录注册到细粒度权限管理的全链路需求,显著降低安全功能的开发与维护成本。 本章系统讲解 Django 认证与授权体系的原理、组件与工程实践,涵盖内置用户模型、认证流程、权限模型、组管理、视图级与模板级权限控制、自定义扩展等核心主题,并提供可直接落地的代码示例与关键配置说明。
在任何 Web 应用程序中,用户认证与授权都是保障系统安全的核心机制。用户认证(Authentication) 用于验证用户身份,确认“你是谁”;用户授权(Authorization) 则在认证通过后,决定用户“能做什么”——即对资源访问、数据操作及功能使用的精细化控制。Django 内置成熟、可扩展且符合安全最佳实践的认证与授权框架,覆盖从基础登录注册到细粒度权限管理的全链路需求,显著降低安全功能的开发与维护成本。
本章系统讲解 Django 认证与授权体系的原理、组件与工程实践,涵盖内置用户模型、认证流程、权限模型、组管理、视图级与模板级权限控制、自定义扩展等核心主题,并提供可直接落地的代码示例与关键配置说明。
认证是验证用户身份的过程,核心目标是确认请求者是否为合法注册用户。Django 通过可插拔的后端机制、标准化表单与会话集成,实现安全、灵活的身份核验。
Django 在 django.contrib.auth.models 中提供开箱即用的 User 模型,已预置生产环境所需的核心字段与安全逻辑:
| 字段名 | 类型 | 说明 |
|---|---|---|
username |
CharField(唯一) |
用户唯一标识符,常用于登录 |
password |
CharField |
加密存储的密码哈希值,非明文 |
email |
EmailField |
邮箱地址,支持找回密码等场景 |
first_name / last_name |
CharField |
用户姓名信息 |
is_active |
BooleanField(默认 True) |
控制账户是否启用,禁用后无法登录 |
is_staff |
BooleanField(默认 False) |
标识是否可访问 Django 管理后台 |
is_superuser |
BooleanField(默认 False) |
拥有所有权限,绕过所有授权检查 |
last_login |
DateTimeField |
最后成功登录时间戳 |
date_joined |
DateTimeField |
账户创建时间 |
✅ 安全要点:
password字段始终存储 PBKDF2HMAC、Argon2 等强哈希算法生成的密文,Django 自动处理加盐与验证,开发者无需手动加密。
代码实践:查看 User 模型字段结构
from django.contrib.auth.models import User # 输出全部字段名(含继承字段) field_names = [f.name for f in User._meta.get_fields()] print(field_names) # ['id', 'password', 'last_login', 'is_superuser', 'username', # 'first_name', 'last_name', 'email', 'is_staff', 'is_active', # 'date_joined']
Django 认证系统采用可插拔后端架构,通过 AUTHENTICATION_BACKENDS 设置定义验证逻辑。默认后端 django.contrib.auth.backends.ModelBackend 基于数据库查询与密码校验,但支持无缝扩展。
认证流程图示
配置说明(settings.py)
# settings.py AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', # 默认数据库认证 # 'myapp.backends.LDAPBackend', # 示例:LDAP 认证 # 'social_core.backends.github.GithubOAuth2', # 示例:GitHub OAuth2 ]
🔑 扩展能力:通过实现
authenticate(request, **credentials)方法,可接入 LDAP、OAuth2、JWT 或生物识别等任意认证源,Django 自动按顺序尝试各后端直至成功。
Django 提供 django.contrib.auth.forms.AuthenticationForm,封装登录表单的字段定义、空值校验及后端调用逻辑,是构建登录页的推荐起点。
自定义登录表单(forms.py)
from django.contrib.auth.forms import AuthenticationForm from django import forms class LoginForm(AuthenticationForm): username = forms.CharField( widget=forms.TextInput(attrs={'placeholder': '请输入用户名'}), error_messages={'required': '用户名不能为空'} ) password = forms.CharField( widget=forms.PasswordInput(attrs={'placeholder': '请输入密码'}), error_messages={'required': '密码不能为空'} )
登录视图(views.py)
from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.views import LoginView from .forms import LoginForm def login_view(request): if request.method == 'POST': form = LoginForm(request, data=request.POST) # 必须传入 request if form.is_valid(): user = form.get_user() login(request, user) # 创建会话,设置 request.user return redirect('home') else: form = LoginForm() return render(request, 'login.html', {'form': form})
模板(login.html)
<form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">登录</button> </form>
✅ 关键机制:
AuthenticationForm.is_valid()内部调用authenticate(),get_user()返回已验证的User实例;login()函数将用户信息写入 session 并绑定至request.user。
Django 提供函数式与类视图双模式支持,兼顾简洁性与可定制性。
| 方式 | 登录函数/视图 | 登出函数/视图 | 特点 |
|---|---|---|---|
| 函数式 | login(request, user) |
logout(request) |
轻量,适合简单逻辑 |
| 类视图 | LoginView |
LogoutView |
支持 template_name、success_url、redirect_field_name 等配置 |
类视图配置示例(views.py)
from django.contrib.auth.views import LoginView, LogoutView from django.urls import reverse_lazy class CustomLoginView(LoginView): form_class = LoginForm template_name = 'login.html' redirect_authenticated_user = True # 已登录用户访问登录页时重定向 success_url = reverse_lazy('home') class CustomLogoutView(LogoutView): next_page = reverse_lazy('home')
URL 配置(urls.py)
from django.urls import path from .views import CustomLoginView, CustomLogoutView urlpatterns = [ path('login/', CustomLoginView.as_view(), name='login'), path('logout/', CustomLogoutView.as_view(), name='logout'), ]
Django 不提供开箱即用的注册视图,但通过 UserCreationForm 可快速构建安全注册流程。
注册表单(forms.py)
from django.contrib.auth.forms import UserCreationForm from django import forms class RegistrationForm(UserCreationForm): email = forms.EmailField( required=True, help_text='请填写有效邮箱,用于密码找回' ) class Meta(UserCreationForm.Meta): fields = ('username', 'email', 'password1', 'password2')
注册视图(views.py)
from django.shortcuts import render, redirect from django.contrib.auth import login from .forms import RegistrationForm def registration_view(request): if request.method == 'POST': form = RegistrationForm(request.POST) if form.is_valid(): user = form.save() # 自动哈希密码并保存 login(request, user) # 注册后立即登录 return redirect('home') else: form = RegistrationForm() return render(request, 'registration.html', {'form': form})
⚠️ 安全提醒:
UserCreationForm自动校验密码强度、一致性及用户名唯一性,切勿手动处理明文密码。
授权解决“已认证用户能否执行某操作”的问题。Django 通过权限(Permissions)→ 组(Groups)→ 视图/模板控制三级机制,实现从模型级到界面级的权限闭环。
权限以 app_label.codename 格式标识(如 blog.add_post),Django 为每个模型自动创建 add/change/delete/view 四类默认权限。
权限检查示例
from django.contrib.auth.models import User user = User.objects.get(username='alice') # 检查是否拥有 blog 应用中 Post 模型的修改权限 if user.has_perm('blog.change_post'): print("允许编辑文章") # 检查是否拥有自定义权限(见 2.5 节) if user.has_perm('blog.publish_post'): print("允许发布文章")
Group 模型用于批量分配权限。将用户加入组,即可继承该组全部权限,大幅提升权限管理效率。
创建编辑组并赋权(Django Shell)
from django.contrib.auth.models import Group, Permission from django.contrib.contenttypes.models import ContentType from blog.models import Post # 获取 Post 模型的内容类型 content_type = ContentType.objects.get_for_model(Post) # 创建组 editors_group = Group.objects.create(name='文章编辑员') # 获取 change_post 权限并添加至组 change_perm = Permission.objects.get( codename='change_post', content_type=content_type ) editors_group.permissions.add(change_perm) # 将用户加入组 user.groups.add(editors_group)
✅ 优势:权限变更只需更新组配置,无需逐个修改用户,符合最小权限原则(Principle of Least Privilege)。
Django 提供装饰器(函数视图)与 Mixin(类视图)两种方式,在请求入口处拦截未授权访问。
| 控制类型 | 函数式装饰器 | 类视图 Mixin | 说明 |
|---|---|---|---|
| 登录要求 | @login_required |
LoginRequiredMixin |
未登录用户重定向至 LOGIN_URL |
| 权限要求 | @permission_required('app.perm') |
PermissionRequiredMixin |
无权限返回 403 Forbidden |
| 自定义逻辑 | @user_passes_test(lambda u: u.email.endswith('@company.com')) |
UserPassesTestMixin |
灵活编写任意验证函数 |
代码示例
# views.py from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin from django.views.generic import TemplateView @login_required def profile_view(request): return render(request, 'profile.html') @permission_required('blog.delete_post', raise_exception=True) def delete_post_view(request, post_id): # ... 删除逻辑 pass class DashboardView(LoginRequiredMixin, TemplateView): template_name = 'dashboard.html' class PostEditView(PermissionRequiredMixin, TemplateView): permission_required = 'blog.change_post' template_name = 'post_edit.html'
在前端动态渲染权限敏感内容,避免用户通过 URL 直接访问未授权页面。
模板语法(base.html)
<!-- 显示仅管理员可见的链接 --> {% if perms.blog.add_post %} <a href="{% url 'post_create' %}">新建文章</a> {% endif %} <!-- 显示仅当前用户可编辑的按钮 --> {% if user.is_authenticated and post.author == user %} <a href="{% url 'post_edit' post.id %}">编辑</a> {% endif %} <!-- 超级管理员专属提示 --> {% if user.is_superuser %} <div class="alert alert-warning">您正在使用超级管理员账户</div> {% endif %}
✅ 前提:确保
django.contrib.auth.context_processors.auth在TEMPLATES['OPTIONS']['context_processors']中启用。
当默认权限无法满足业务需求时,可在模型 Meta 中声明自定义权限。
模型定义(models.py)
from django.db import models class Post(models.Model): title = models.CharField(max_length=200) content = models.TextField() author = models.ForeignKey('auth.User', on_delete=models.CASCADE) class Meta: permissions = [ ('publish_post', 'Can publish post to homepage'), # codename + description ('review_post', 'Can review pending posts'), ]
迁移与使用
执行 python manage.py makemigrations && python manage.py migrate 后,权限自动注册至数据库,可直接通过 user.has_perm('blog.publish_post') 检查。
当内置 User 模型无法满足需求(如需邮箱登录、手机号字段、多租户支持),应在项目初期创建自定义模型。
推荐方案:继承 AbstractUser
# models.py from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): phone = models.CharField(max_length=20, blank=True, null=True) avatar = models.ImageField(upload_to='avatars/', blank=True) # 可选:将邮箱设为登录字段(需配合自定义后端) EMAIL_FIELD = 'email' USERNAME_FIELD = 'email' # 登录字段改为 email REQUIRED_FIELDS = ['username'] # 创建超级用户时必填字段
配置(settings.py)
# settings.py AUTH_USER_MODEL = 'myapp.CustomUser' # 格式:app_label.ModelName
⚠️ 重要:
AUTH_USER_MODEL必须在首次迁移前设置,否则需重建数据库或执行复杂迁移。
Django 内置完整密码生命周期管理:
PasswordResetView + PasswordResetConfirmView 支持邮箱令牌重置PasswordChangeView 强制新旧密码校验安全加固建议
SECURE_SSL_REDIRECT = True)django-axes 限制暴力尝试PASSWORD_MIN_LENGTH = 12 及 PASSWORD_REQUIRE_DIGIT = True(通过 django-password-validators)通过 django-allauth 等成熟库,可快速集成 GitHub、Google、微信等 OAuth2 登录:
pip install django-allauth
核心优势
✅ 用户免密注册,降低流失率
✅ 复用平台安全能力(如双因素、风控)
✅ 支持社交账号关联与统一身份管理
Django 的认证与授权系统以模块化、可扩展、安全默认为设计哲学,为开发者提供从基础到高级的完整工具链:
User 模型、认证后端、表单与会话,实现身份核验的灵活性与安全性;最佳实践清单
🔹 始终优先使用 @login_required 和 PermissionRequiredMixin 进行视图保护
🔹 敏感操作(如删除、支付)必须在视图中二次校验权限,不依赖前端隐藏
🔹 定期审计 Group 权限分配,遵循最小权限原则
🔹 自定义用户模型应在项目启动阶段确定,避免后期重构风险
🔹 生产环境启用 SECURE_SSL_REDIRECT 和 SESSION_COOKIE_SECURE
掌握本章内容,开发者即可构建符合金融、政务、企业级标准的安全 Web 应用,为业务增长筑牢信任基石。