继承basepermission实现自定义权限类:必须重写has_permission或has_object_permission方法,显式返回true/false;需先检查request.user.is_authenticated再访问其属性;全局权限用has_permission,对象级权限用has_object_permission且依赖get_object()触发。

如何继承 BasePermission 实现自定义权限类
DRF 的权限系统靠返回 True 或 False 决定是否放行,自定义类必须继承 BasePermission 并重写 has_permission(self, request, view) 或 has_object_permission(self, request, view, obj)。
常见错误是直接返回字符串或没处理 request.user 未认证的情况——未登录用户 request.user 是 AnonymousUser,它没有 is_authenticated 以外的属性,强行访问 user.profile.role 会抛 AttributeError。
实操建议:
-
has_permission控制是否能进入视图(如列表页、创建接口),适合做角色判断、IP 白名单等全局检查 -
has_object_permission在get_object()后调用,用于对象级控制(如“只能编辑自己的文章”),此时obj已存在且非None - 两个方法都必须显式返回
False拒绝,不能只写逻辑不返回——Python 函数默认返回None,而 DRF 把None当作拒绝处理,但这是隐式行为,易引发调试困惑
为什么 SAFE_METHODS 要单独判断
GET、HEAD、OPTIONS 属于安全方法,通常只读,很多业务允许游客查看但禁止修改。若权限逻辑没区分,会导致 AnonymousUser 在 POST 时被拒,却在 GET 时因未覆盖判断而意外通过(比如忘了加 if request.method in SAFE_METHODS: return True)。
典型场景:博客系统中,所有人可读文章,但仅作者或管理员可删改。代码里常这么写:
from rest_framework import permissions from django.contrib.auth.models import User <p>class IsOwnerOrAdmin(permissions.BasePermission): def has_object_permission(self, request, view, obj): if request.method in permissions.SAFE_METHODS: return True return obj.author == request.user or request.user.is_staff </p>
注意:permissions.SAFE_METHODS 是元组 ('GET', 'HEAD', 'OPTIONS'),别手写字符串,避免大小写或拼写错误。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
如何在 ViewSet 中正确配置多个权限类
DRF 权限是“与”关系:所有权限类都返回 True 才放行。比如同时需要登录 + 角色校验 + IP 限制,就往 permission_classes 列表里加多个类。
容易踩的坑:
- 把
IsAuthenticated和自定义类顺序写反——虽然顺序不影响逻辑结果,但若自定义类依赖request.user.is_authenticated,放在IsAuthenticated前面可能导致未认证用户直接进到你的逻辑里,增加异常风险 - 在
GenericAPIView子类中误用permission_classes = [MyPermission]却忘了它只对当前视图生效,而ViewSet的 action(如create、update)可能需不同权限,这时得用def get_permissions(self):动态返回 - 使用
@action定义额外接口时,权限不会自动继承,必须显式传permission_classes=[...]
调试权限失败时看不到具体原因?
DRF 默认拒绝请求时只返回 403 Forbidden 或 401 Unauthorized,不告诉你卡在哪一个权限类。要定位问题,可在自定义类中加日志或临时打印:
def has_permission(self, request, view):
print(f"[DEBUG] user={request.user}, method={request.method}, auth={request.user.is_authenticated}")
if not request.user.is_authenticated:
return False
# ... 其他逻辑
更稳妥的做法是复写 message 属性或抛出带提示的异常,但注意:DRF 不会把异常消息透出给前端(除非 DEBUG=True 且没捕获),生产环境建议用日志而非 print。
真正复杂的地方在于权限嵌套——比如某个 API 需同时满足“用户属于某部门”+“该部门有此功能开关开启”+“操作对象未过期”,这类逻辑一旦散落在多个权限类里,就很难维护和测试。不如收拢到一个类中,用清晰的条件分支和注释说明每条规则的业务依据。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










