浏览知识库目录

Python

用户认证与权限控制

用户认证与权限控制

本篇使用 Django 内置认证系统实现登录、退出、注册、访问限制和对象级权限。认证回答“你是谁”,授权回答“你能做什么”。


一、内置认证系统包含什么

Django 默认提供:

  • 用户与密码哈希。
  • 登录、退出和会话。
  • 用户组与模型权限。
  • 密码修改与重置视图。
  • request.userlogin_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。


七、模型权限与用户组

每个模型默认生成 addchangedeleteview 权限。

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_URLnext
  • request.user 不存在:认证中间件被移除或顺序错误。
  • 密码永远验证失败:直接写入了 password,没有使用哈希方法。
  • 用户可以编辑别人的数据:View 只按 pk 查询,没有限制 owner。
  • 自定义用户模型迁移冲突:在已有大量迁移后才修改 AUTH_USER_MODEL

十、本篇检查清单

  • 能使用内置登录、退出和密码重置路由。
  • 能实现注册并安全设置密码。
  • 能限制匿名用户访问。
  • 能在服务端实施对象级权限。
  • 理解用户组、模型权限和对象归属的区别。

上一篇:CRUD、分页、搜索与消息框架 | 下一篇:类视图与通用视图