DRF中IsAuthenticated未生效最常见的原因是权限类未正确注册到视图或全局配置;必须显式声明permission_classes=[IsAuthenticated],且多个权限类需全部返回True才通过,顺序不可颠倒。

DRF里IsAuthenticated为什么没生效?
最常见的原因是权限类没正确注册到视图或全局配置里,而不是代码写错了。DRF默认不启用任何权限,IsAuthenticated必须显式声明才会起作用。
- 全局配置写在
settings.py的REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES']里,但一旦写了,所有视图都受约束——包括APIView、ViewSet甚至未登录时的登录接口本身,容易导致401循环 - 更安全的做法是只在具体视图上加:
permission_classes = [IsAuthenticated],尤其适合混合权限场景(比如列表页公开、详情页需登录) - 注意:如果视图继承自
APIView,必须用permission_classes属性;若用ViewSet,同样适用,但动作级控制得靠get_permissions()方法
自定义BasePermission怎么写才不踩坑?
核心就一条:has_permission(self, request, view)返回True或False,别抛异常、别返回字符串、别漏写self——这是最常被复制粘贴错的地方。
- 判断逻辑里别直接访问
request.user而忘了检查is_authenticated,未登录用户request.user是AnonymousUser,它没有is_active等属性,会抛AttributeError - 需要对象级权限时(比如编辑某条订单),必须实现
has_object_permission(self, request, view, obj),且视图得调用get_object()触发它——单纯list()不会走这个方法 - 多个权限类同时存在时,DRF按顺序执行,**全部返回
True才算通过**,所以别把IsAuthenticated和自定义类顺序搞反,否则未登录就直接短路失败
IsAuthenticated和自定义权限能一起用吗?
能,而且推荐这么用:用IsAuthenticated兜底身份,再用自定义类做业务判断。但要注意组合方式不是“或”,而是“与”。
- 写法是:
permission_classes = [IsAuthenticated, IsOwnerOrReadOnly],DRF会依次调用每个类的has_permission - 如果自定义类里重复做了认证判断(比如又查了一遍
request.user.is_authenticated),纯属冗余;交给IsAuthenticated处理更清晰 - 有个隐藏陷阱:
IsAuthenticated对OPTIONS请求默认放行,但你的自定义类如果没覆盖has_permission对OPTIONS的处理,可能意外拒绝预检请求——前端发CORS请求时会卡住
为什么get_permissions()比permission_classes属性更灵活?
因为它是运行时方法,能根据request.method、view.action甚至URL参数动态决定权限,避免为同一资源写多个视图类。
- 在
ViewSet里,action可能是'list'、'retrieve'、'update'等,你可以这样分流:if view.action in ['update', 'destroy']: return [IsOwnerOrReadOnly] - 注意别在
get_permissions()里硬编码权限实例(比如[MyPermission()]),应该返回类名列表,让DRF自己实例化——否则每次调用都新建对象,可能引发状态污染 - 如果某个动作要完全跳过权限(比如公开的健康检查接口),返回空列表
[]即可,但得确认这是否符合安全要求
dispatch()早期运行,拿不到序列化后的数据,也看不到数据库查询结果。所有依赖对象字段的判断,必须在has_object_permission里做,而且确保get_object()真被调用了。


















