Axes Integration¶
Use django-axes for brute-force protection, with limits controlled from SecuritySettings (no restart).
Requires: pip install "nai-security[axes]" (django-axes >= 8.3.1, < 9).
settings.py¶
INSTALLED_APPS = [
# ...
"axes",
"nai_security",
]
AUTHENTICATION_BACKENDS = [
"axes.backends.AxesStandaloneBackend",
"django.contrib.auth.backends.ModelBackend",
]
AXES_HANDLER = "nai_security.handlers.axes_integration.DynamicAxesHandler"
AXES_FAILURE_LIMIT = 5 # fallback if DB settings cannot be read
AXES_COOLOFF_TIME = None # overridden dynamically from SecuritySettings
Also include Axes middleware per django-axes docs for your Django version.
Admin-controlled fields¶
In SecuritySettings:
| Field | Meaning |
|---|---|
| Max login attempts | Failures before lockout |
| Cooloff minutes | Auto-unlock delay (0 = until manual reset) |
| Attempt expiry enabled | Each failure expires independently (requires cooloff > 0) |
Validation: attempt expiry cannot be enabled when cooloff is 0.
Whitelist bypass (important)¶
DynamicAxesHandler skips axes lockout when:
- Client IP is in
WhitelistedIP, or - Login user matches an active
WhitelistedUser(anyexemption_type)
Notes:
- IP whitelist works even on credential-less requests (e.g. GET login page)
- Username lookup falls back to email when login form posts email but
USERNAME_FIELDisusername - Failed logins for whitelisted requests are not written to
AccessAttempt
exemption_type still controls middleware bypasses only. For axes, whitelist presence is binary.
Manual unlock¶
Use Axes admin / nai-security admin actions (where available) to clear lockouts for a user/IP.