DRF DjangoModelPermissions 拒绝已授权认证用户访问问题排查
DRF接口返回403权限拒绝排查修复方案
你当前已完成的验证场景如下:
- 权限配置核查:

- Shell授权操作记录:

- Postman接口测试返回权限拒绝:

- 当前视图代码:
class UserList(generics.ListCreateAPIView): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [DjangoModelPermissions] class UserDetail(generics.RetrieveUpdateDestroyAPIView): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [DjangoModelPermissions]
按以下优先级排查修复即可:
1. 先排查认证环节是否正常
DjangoModelPermissions 生效的前提是请求能通过认证类识别到合法登录用户,拿不到有效用户时会直接判定为匿名用户返回403,哪怕后台已经给对应用户分配了权限也不会生效。
- 调试方法:在视图中加入打印逻辑输出
request.user,如果返回AnonymousUser,说明认证环节失效:- 用Session认证的场景,检查Postman是否携带了有效会话Cookie、开启跨请求保持会话,POST/PUT/DELETE请求是否携带合法CSRF Token
- 用Token/JWT认证的场景,检查请求头
Authorization的格式、Token值是否正确,是否存在Token过期、拼写错误问题
如果超级用户账号访问依旧返回403,可直接判定为认证环节失效或代码配置未生效,优先排查认证逻辑和代码缩进问题。
2. 排查权限缓存不生效问题
Django会在用户登录时把全量权限缓存到会话中,如果你是在用户已经登录的状态下,通过Shell或者后台给用户新增权限,当前会话里的权限数据不会自动更新,会一直判定为无权限。
- 修复方法:让对应用户退出登录后重新登录,拉取最新的权限数据再测试;如果用了外部权限缓存(比如Redis存权限),先清空对应缓存再测试。
- 权限有效性验证:在Shell中对应用户下执行
print(user.get_all_permissions()),确认输出的权限集合中包含当前请求需要的权限标识。
3. 核对权限映射规则与权限标识
DjangoModelPermissions 默认的权限映射规则不包含GET类请求的查看权限校验,具体对应关系如下:
| 请求方法 | 所需权限标识格式 |
|---|---|
| POST | {app_label}.add_{model_name} |
| PUT/PATCH | {app_label}.change_{model_name} |
| DELETE | {app_label}.delete_{model_name} |
| GET/HEAD/OPTIONS | 无默认权限要求 |
- 如果你是GET请求被拦截,要么是全局配置了其他权限类拦截,要么是需要自定义权限类加入view权限校验,参考代码:
from rest_framework.permissions import DjangoModelPermissions class DjangoModelPermsWithView(DjangoModelPermissions): perms_map = { 'GET': ['%(app_label)s.view_%(model_name)s'], 'HEAD': [], 'OPTIONS': [], 'POST': ['%(app_label)s.add_%(model_name)s'], 'PUT': ['%(app_label)s.change_%(model_name)s'], 'PATCH': ['%(app_label)s.change_%(model_name)s'], 'DELETE': ['%(app_label)s.delete_%(model_name)s'], }
- 核对权限标识的app_label和model_name完全匹配:如果用Django默认User模型,权限前缀是
auth,比如auth.add_user;如果是自定义User模型在users应用下,前缀是users,标识错误的权限不会被识别。
4. 修复代码格式错误
你贴出的视图代码存在严重的缩进问题:Python类的属性必须相对class声明行缩进4个空格,当前代码中queryset、serializer_class、permission_classes 都和class行顶格对齐,根本不属于视图类的属性,会导致视图读取全局默认配置,权限类、查询集配置不生效。
修正后的正确代码格式:
class UserList(generics.ListCreateAPIView): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [DjangoModelPermsWithView] # 如需GET校验权限替换为自定义类 class UserDetail(generics.RetrieveUpdateDestroyAPIView): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [DjangoModelPermsWithView]
验证顺序
- 修正代码缩进,重启服务
- 打印
request.user确认拿到的是目标授权用户 - 重新登录刷新权限缓存,确认
user.get_all_permissions()返回对应权限 - 检查Postman认证参数传递正确
- 如果是GET请求,替换为带view权限校验的自定义权限类
内容的提问来源于stack exchange,提问作者Mr.Andor
相关产品推荐
相关产品推荐

