Python
用户认证与权限控制
发布于 2026年7月23日
用户认证与权限控制
本篇使用 Django 内置认证系统实现登录、退出、注册、访问限制和对象级权限。认证回答“你是谁”,授权回答“你能做什么”。
一、内置认证系统包含什么
Django 默认提供:
- 用户与密码哈希。
- 登录、退出和会话。
- 用户组与模型权限。
- 密码修改与重置视图。
request.user、login_required和权限 Mixin。
密码必须通过 set_password() 或 create_user() 设置,不能把明文直接写入 password 字段。
二、接入内置登录路由
项目根 urls.py:
from django.urls import include, path
urlpatterns = [
path("accounts/", include("django.contrib.auth.urls")),
path("messages/", include("notes.urls")),
]
它会注册登录、退出、密码修改和密码重置等路由。
settings.py:
LOGIN_URL = "login"
LOGIN_REDIRECT_URL = "notes:list"
LOGOUT_REDIRECT_URL = "notes:list"
创建 templates/registration/login.html:
{% extends "base.html" %}
{% block content %}
<h1>登录</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
{% if next %}<input type="hidden" name="next" value="{{ next }}">{% endif %}
<button type="submit">登录</button>
</form>
<a href="{% url 'password_reset' %}">忘记密码</a>
{% endblock %}
退出是状态变更操作。新版本 Django 的内置退出视图使用 POST,应使用表单按钮而不是普通链接:
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button type="submit">退出</button>
</form>
三、注册用户
from django.contrib.auth import login
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import redirect, render
def signup(request):
form = UserCreationForm(request.POST or None)
if request.method == "POST" and form.is_valid():
user = form.save()
login(request, user)
return redirect("notes:list")
return render(request, "registration/signup.html", {"form": form})
如果需要邮箱、昵称等字段,可以自定义注册 Form。不要为了多几个资料字段就急着修改用户模型;但如果项目确定要用邮箱登录,应在第一次迁移前设计自定义用户模型。
四、自定义用户模型
新项目推荐尽早建立可扩展用户模型:
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
display_name = models.CharField(max_length=50, blank=True)
settings.py:
AUTH_USER_MODEL = "users.User"
更换用户模型应在项目首次 migrate 前完成。中途更换涉及外键和迁移历史,成本很高。
五、限制登录访问
函数视图:
from django.contrib.auth.decorators import login_required
@login_required
def message_create(request):
# 原有逻辑
...
类视图:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView
class MessageCreateView(LoginRequiredMixin, CreateView):
model = Message
fields = ["name", "content"]
LoginRequiredMixin 通常放在继承列表最左侧。
六、对象级权限
Django 内置模型权限不自动解决“只能编辑自己的留言”。最直接的做法是在查询阶段限定 owner:
@login_required
def message_update(request, pk):
message = get_object_or_404(Message, pk=pk, owner=request.user)
# 后续更新逻辑
这样无权访问时返回 404,不会泄露该对象是否存在。
若管理员也可编辑:
from django.core.exceptions import PermissionDenied
if message.owner != request.user and not request.user.is_staff:
raise PermissionDenied
仅在模板里隐藏“编辑”按钮不构成权限控制,用户仍可直接请求 URL。
七、模型权限与用户组
每个模型默认生成 add、change、delete、view 权限。
from django.contrib.auth.decorators import permission_required
@permission_required("notes.change_message", raise_exception=True)
def moderation(request):
...
模板中可以检查:
{% if perms.notes.change_message %}
<a href="...">审核留言</a>
{% endif %}
用户组适合表达角色,例如“编辑”“审核员”“客服”。把权限授予组,再把用户加入组,比逐个用户授权更易维护。
八、会话与登录安全
request.session["theme"] = "light"
theme = request.session.get("theme", "light")
会话中只保存必要的小数据,不要保存模型实例、密码、令牌或大量内容。
安全要点:
- 全站使用 HTTPS。
- 登录后执行 Django 的
login(),它会处理会话标识轮换。 - 密码重置邮件中的域名和协议要正确配置。
- 对登录、注册、找回密码增加速率限制。
- 管理员启用强密码和多因素认证方案。
九、常见问题
- 登录成功又回到登录页:检查
LOGIN_REDIRECT_URL和next。 request.user不存在:认证中间件被移除或顺序错误。- 密码永远验证失败:直接写入了
password,没有使用哈希方法。 - 用户可以编辑别人的数据:View 只按
pk查询,没有限制 owner。 - 自定义用户模型迁移冲突:在已有大量迁移后才修改
AUTH_USER_MODEL。
十、本篇检查清单
- 能使用内置登录、退出和密码重置路由。
- 能实现注册并安全设置密码。
- 能限制匿名用户访问。
- 能在服务端实施对象级权限。
- 理解用户组、模型权限和对象归属的区别。
上一篇:CRUD、分页、搜索与消息框架 | 下一篇:类视图与通用视图