You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试中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。

有两种解决方式:

  1. 清除用户权限缓存
    在添加权限后,手动清除缓存或刷新用户对象:

    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()刷新对象数据。

  2. 重新获取用户实例
    从数据库重新拉取用户对象,跳过缓存:

    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:32:37