引入 django-axes 后测试出现问题
Source: Dev.to
背景
什么是 django-axes?
django-axes 是一个 Django 包,用于监控登录尝试并根据认证设置锁定用户。它有助于防止暴力破解攻击。
我为什么使用 django-axes
我在一个协作项目中开发一个带登录功能的小应用。为了防止暴力破解攻击,我们想限制登录尝试次数,于是决定引入 django-axes。
问题
在实现 django-axes 后,我运行了所有测试。许多之前通过的测试开始失败。所有失败都与登录功能有关,因为测试中没有包含请求对象。
当测试使用 client.login(如下所示)时,用户会在没有 HTTP 请求的情况下被认证。然而,django-axes 通过检查请求来判断用户是否已认证,导致了这些失败。
失败的模式(使用 client.login)
self.user = User.objects.create_user(
username="login_user",
email="login@example.com",
password="LoginPass123",
)
self.client.login(email="login@example.com", password="LoginPass123")
正常的模式(使用 client.post)
self.user = User.objects.create_user(
username="login_user",
email="login@example.com",
password="LoginPass123",
)
self.client.post(
self.login_url,
{"email": "login@example.com", "password": "LoginPass123"},
REMOTE_ADDR="192.168.1.1",
)
解决方案
我找到了两种实用的解决办法。
1. 在测试中禁用 django-axes
在测试配置中设置 AXES_ENABLE = False,即可在测试期间关闭 django-axes 检查。
当需要测试与 django-axes 相关的功能时,再将其重新设为 AXES_ENABLE = True。
这种做法可以让你仅在真正需要的测试中启用 django-axes 行为。
2. 使用 force_login()
force_login() 绕过了 django-axes 所挂钩的认证过程。对于与登录验证本身无关的测试,使用 force_login() 替代 client.login() 是合理的。
正常的模式(使用 force_login)
self.user = User.objects.create_user(
username="login_user",
email="login@example.com",
password="LoginPass123",
)
self.client.force_login(self.user)
如前所述,使用 client.post() 也能正常工作,因为它会包含请求对象。
结论
django-axes 是一个非常有用的包,能够提升应用的安全性。但在引入它时,需要注意测试中认证的处理方式。根据应用架构和测试策略,选择最合适的方案——要么在测试中禁用 django-axes,要么使用 force_login() / client.post() 进行认证。
希望这能帮助遇到类似问题的朋友。