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

Django测试客户端登录用户后访问视图被重定向至登录页

Django测试中client.login生效但访问视图后自动退出的问题

问题现象

在Django测试中调用client.login()后,看似登录成功,但访问目标视图时用户会被强制退出,重定向至登录页。即使使用force_login()方法,问题依然存在。额外细节:

  • 调用login()后get_user(self.client)返回正常用户,但访问视图后变回AnonymousUser
  • 重定向地址从http://localhost/...变为http://testserver/...
  • 开发环境为Docker容器,用户模型继承自AbstractUser,无自定义登录逻辑

可复现代码

from django.auth import get_user
from django.test import TestCase
from django.urls import reverse
import logging

logger = logging.getLogger(__name__)

class MapListViewTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        # 创建用户
        cls.user = get_user_model().objects.create(username="testuser")
        cls.user.set_password("password")
        cls.user.save()

    def setUp(self):
        # 尝试登录
        self.client.login(
            username=self.user.get_username(), password="password"
        )

    def test_map_list_view_renders(self):
        """测试MapListView能否成功渲染并包含地图列表"""
        logger.info(get_user(self.client)) # <-- 初始为AnonymousUser
        
        self.client.login(
            username=self.user.get_username(), password="password"
        )
        logger.info(get_user(self.client)) # <-- 登录后为正常用户

        response = self.client.get(reverse("map_list"), follow=True)
        logger.info(get_user(self.client)) # <-- 访问视图后变回AnonymousUser

        self.assertEqual(response.status_code, 200) # <-- 测试通过(因follow了重定向)
        self.assertTemplateUsed(response, "map_list.html") # <-- 实际使用account/login.html

排查与解决方案

1. 确认登录操作是否真的成功

client.login()会返回布尔值表示登录状态,先添加断言确认登录有效性:

def setUp(self):
    login_success = self.client.login(username=self.user.username, password="password")
    self.assertTrue(login_success, "登录失败,请检查用户名密码是否匹配")

同时可验证用户密码是否正确保存:

self.assertTrue(self.user.check_password("password"))

2. 检查视图的认证逻辑

  • 确认MapListView是否使用@login_required装饰器或LoginRequiredMixin,排查自定义权限验证逻辑是否误判用户权限
  • 检查项目中自定义中间件,尤其是涉及认证、会话处理的中间件,是否主动修改或清空了用户状态

3. 解决域名/会话Cookie不匹配问题

测试客户端默认使用testserver域名,若项目配置硬编码localhost相关设置(如SESSION_COOKIE_DOMAIN、CSRF_TRUSTED_ORIGINS),会导致会话Cookie无法被识别:

  • 在测试中显式设置客户端base_url:
    def setUp(self):
        self.client.base_url = "http://localhost:8000"
        self.client.force_login(self.user)
    
  • 或在测试环境settings中调整:
    # 测试环境settings.py
    SESSION_COOKIE_DOMAIN = None
    CSRF_TRUSTED_ORIGINS = ["http://testserver", "http://localhost"]
    

4. 正确使用force_login方法

force_login无需密码,直接传入用户对象即可,确保用法正确:

def setUp(self):
    self.client.force_login(self.user)

若使用后仍失效,重点排查视图或中间件是否主动登出用户。

5. 检查会话是否被清空

在访问视图前后打印会话内容,确认认证相关键(如_auth_user_id)是否消失:

logger.info(self.client.session.items()) # 访问前打印会话
response = self.client.get(reverse("map_list"), follow=True)
logger.info(self.client.session.items()) # 访问后打印会话

内容的提问来源于stack exchange,提问作者danilociaffi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 01:27:11