← 返回题目列表

Django 的认证和权限系统是怎么工作的?

高频 中等 第 2 / 27 题 更新于 2026/07/27
Django认证权限Session

简化版

Django 内置认证系统主要负责用户、登录、登出、密码哈希、Session 认证、权限和分组。请求经过 SessionMiddleware 与 AuthenticationMiddleware 后,会在 request.user 上得到当前用户;权限可以通过用户、组和 permission 进行判断。

详细版

Django 认证体系常见组件:

  • User 模型:保存用户名、密码哈希、邮箱、状态等;
  • 密码哈希:不会明文保存密码;
  • 登录登出:login()logout()
  • request.user:当前请求用户,未登录通常是 AnonymousUser;
  • Session:登录态通常保存在服务端 Session + 客户端 Cookie 标识中;
  • Permission:基于模型的 add/change/delete/view 权限;
  • Group:把权限分组后批量赋给用户;
  • 装饰器和 mixin:例如 login_requiredPermissionRequiredMixin

面试时要说清楚:认证解决“你是谁”,权限解决“你能做什么”。二者相关但不是一回事。

完整版教学

一、认证和权限的边界

认证 Authentication 关注身份:

这个请求是谁发的?是否已经登录?

权限 Authorization 关注授权:

这个用户能不能访问这个资源或执行这个动作?

一个用户可以已经登录,但没有删除文章的权限;也可以未登录,只能访问公开页面。

二、登录态如何挂到 request.user

典型中间件顺序中有:

MIDDLEWARE = [
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
]

SessionMiddleware 根据 Cookie 找到服务端 session 数据;AuthenticationMiddleware 再基于 session 里的用户 ID 加载用户,并挂到 request.user

视图里可以这样判断:

def profile(request):
    if request.user.is_authenticated:
        ...

未登录时,request.user 通常是 AnonymousUser,而不是 None。这是一个常见细节。

三、密码为什么不能明文保存

Django 保存的是密码哈希,不是原始密码。用户登录时,框架会把输入密码按对应算法处理后与存储值比较。

这有几个好处:

  • 数据库泄露时,攻击者不能直接拿到明文密码;
  • 可以配置更强的哈希算法;
  • 支持密码哈希算法升级;
  • 内置校验和密码重置流程更安全。

面试时不要只说“加密密码”。更准确的说法是“使用带盐的密码哈希”,因为哈希通常不可逆,而加密通常可逆。

四、权限系统怎么组织

Django 对每个模型通常会生成基础权限:

  • add:增加;
  • change:修改;
  • delete:删除;
  • view:查看。

可以判断用户是否有权限:

if request.user.has_perm("blog.change_article"):
    ...

Group 是权限集合。把权限赋给组,再把用户加入组,比逐个用户配置权限更好维护。

五、常见保护方式

函数视图:

from django.contrib.auth.decorators import login_required, permission_required

@login_required
def profile(request):
    ...

@permission_required("blog.change_article")
def edit_article(request):
    ...

类视图:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView

class ProfileView(LoginRequiredMixin, TemplateView):
    template_name = "profile.html"

这类封装比每个视图手写判断更统一。

六、自定义用户模型的注意点

Django 项目如果需要自定义用户模型,最好在项目初期就配置 AUTH_USER_MODEL。项目上线后再替换用户模型会牵涉外键、迁移和第三方应用,成本很高。

常见建议是:即使早期只用默认字段,也可以先继承 AbstractUser 建一个自定义用户模型,为以后扩展手机号、头像、组织等字段留空间。

七、常见误区

  • 把认证和权限混为一谈。登录不代表拥有操作权限。
  • 认为 request.user 未登录时是 None。通常是 AnonymousUser。
  • 明文存密码或自己设计密码算法。应使用 Django 内置密码哈希体系。
  • 上线后才想替换 User 模型,迁移成本很高。
  • 只在前端隐藏按钮,不在后端校验权限。前端隐藏不是安全控制。

八、认证和权限在 DRF 中怎么对应

如果项目使用 Django REST Framework,认证和权限会进一步拆成 Authentication、Permission、Throttle 等组件。Authentication 负责识别“你是谁”,例如 SessionAuthentication、TokenAuthentication、JWTAuthentication;Permission 负责判断“你能不能访问”,例如 IsAuthenticated、IsAdminUser、自定义对象权限。

这和 Django 内置认证并不冲突。DRF 的认证类最终也会设置 request.userrequest.auth,权限类再基于它们判断是否允许访问。面试时可以说:Django 内置 auth 提供用户、组、权限、登录态等基础能力,DRF 在 API 层提供更细粒度的认证和权限扩展点。

常见误区是把认证失败和权限失败混在一起。认证失败是系统无法确认用户身份,通常返回 401;权限失败是已经知道用户是谁,但不允许访问,通常返回 403。具体状态码还会受认证方案和框架配置影响,但概念上要区分。

九、安全实践:不要只会调用 login

真实项目里,认证权限系统还要考虑密码安全、会话安全和权限粒度。Django 默认使用安全的密码哈希机制,不应该明文保存密码;Session Cookie 应配置 HttpOnlySecureSameSite 等属性;后台敏感操作应结合 CSRF、防重放、审计日志。

权限粒度也要设计清楚。模型级权限适合控制“能不能增删改查某类对象”,对象级权限适合控制“能不能操作某一条数据”。例如用户可以修改自己的文章,但不能修改别人的文章,这就不是简单的全局 change_article 能完全表达的,需要在视图或权限类中结合对象所有者判断。

面试时可以按“认证、授权、会话、安全配置、对象权限”这条线回答。这样答案会从“Django 有 User 和 Permission”升级成完整的安全模型。

十、常见误区与追问

概念回答的问题Django/DRF 中的体现
认证你是谁login、session、Authentication
权限你能做什么Permission、Group、Permission class
会话安全身份如何持续可信Cookie 属性、CSRF、过期策略
  • 误区:登录成功就代表有所有权限。 认证只确认身份,授权还要判断用户、组、模型权限或对象级权限。
  • 误区:未登录时 request.user 是 None。 Django 通常给出 AnonymousUser,所以判断时应使用 request.user.is_authenticated
  • 误区:前端隐藏按钮就完成权限控制。 后端视图、接口或权限类必须再次校验,否则直接请求接口仍可能越权。
  • 追问:为什么密码不能自己加密保存? 应使用 Django 内置密码哈希体系,它包含盐、算法标识和可升级策略,比自定义方案可靠。
  • 追问:什么时候需要自定义 User 模型? 需要手机号登录、组织字段、头像等扩展时应尽早配置 AUTH_USER_MODEL,上线后替换成本很高。
  • 追问:DRF 中 401 和 403 怎么区分? 401 更偏认证失败或缺少有效凭证,403 更偏已识别身份但权限不足,具体表现受认证方案影响。

记忆钩子:认证回答“是谁”,权限回答“能不能”,会话安全回答“身份怎么安全地持续”;三层都讲到,答案才完整。

十一、加强记忆

Django 认证系统回答“用户是谁”,权限系统回答“用户能做什么”。SessionMiddleware 和 AuthenticationMiddleware 配合把用户挂到 request.user;密码保存用哈希;权限通过 user、group、permission 管理;后端必须做权限校验,不能只靠前端隐藏入口。