测试中APIClient两次认证后请求失败问题排查
问题解答
一、为什么返回403而非401?
DRF中,NotAuthenticated异常返回403是因为权限类的执行优先级高于认证类。当请求未通过认证时,若视图使用IsAuthenticated这类权限类,权限检查会先判定用户未登录,直接返回403;而401通常是认证类(如TokenAuthentication)验证失败时返回的,且会附带WWW-Authenticate响应头。
如果需要让未认证请求返回401,可通过配置或自定义实现:
- 在
settings.py中调整DRF配置:REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, } - 自定义权限类,在
has_permission方法中主动抛出AuthenticationFailed异常(会触发401响应)。
二、测试中权限更新后仍返回403的解决方案
这不是Django版本或APIClient的使用错误,核心原因是Django的权限缓存机制:当第一次通过client.force_authenticate(user)认证后,用户的权限列表会被缓存到user._perm_cache属性中。后续给用户添加权限时,缓存不会自动更新,导致DRF仍使用旧权限判断,返回403。
有两种解决方式:
清除用户权限缓存
在添加权限后,手动清除缓存或刷新用户对象:user.user_permissions.add(permission) user._perm_cache = None # 清除权限缓存 client.force_authenticate(user) response = client.get(url) assert response.status_code == 200或者调用
user.refresh_from_db()刷新对象数据。重新获取用户实例
从数据库重新拉取用户对象,跳过缓存:user.user_permissions.add(permission) user = User.objects.get(pk=user.pk) # 重新获取用户 client.force_authenticate(user) response = client.get(url) assert response.status_code == 200
建议测试时尽量为每个权限变更场景使用独立用户实例,或确保权限修改后刷新用户状态,避免缓存干扰。
内容的提问来源于stack exchange,提问作者Gerry
相关产品推荐
相关产品推荐

