django-axes
django-axes is a Django plugin that actively monitors and tracks suspicious login attempts, helping to protect Django-powered sites from brute-force attacks. It can lock out users or IP addresses after a configurable number of failed attempts, supporting various tracking methods like IP, username, and user agent combinations. The library is currently at version 8.3.1 and is actively maintained by the Jazzband community, with a regular release cadence.
Warnings
- breaking Version 8.0.0 moved all database-related logic into `axes.handlers.database.AxesDatabaseHandler`. If you had custom handlers or directly accessed internal database functions related to attempts, you will need to refactor your code to use the new handler methods.
- breaking Version 7.0.0 introduced significant breaking changes related to dynamic cooloff time calculation and lockout response handling. The lockout response calculation changed to request flagging instead of throwing exceptions, and `axes.request.AxesHttpRequest` object type definition was deprecated.
- gotcha As of version 7.0.2, `AXES_USERNAME_FORM_FIELD` now defaults to `settings.AUTH_USER_MODEL.USERNAME_FIELD`. Previously, it hardcoded to 'username'. If you use a custom user model with a different username field or a custom login form with a non-standard username field name (e.g., 'email'), you must explicitly set `AXES_USERNAME_FORM_FIELD` in your `settings.py` to prevent `AccessAttempt` records from having a `None` username.
- gotcha Incorrect order of `AUTHENTICATION_BACKENDS` can lead to axes not functioning correctly. `AxesStandaloneBackend` (or `AxesBackend`) *must* be the first item in your `AUTHENTICATION_BACKENDS` list in `settings.py`.
- gotcha If using a multi-process server (e.g., Gunicorn with multiple workers) or a distributed environment, using `django.core.cache.backends.locmem.LocMemCache` or `FileBasedCache` as your cache backend can lead to inconsistent behavior for Axes, as attempts might not be shared across processes.
- gotcha Prior to version 5.32, a common behavior was that the cool-off timer would reset on any subsequent failed login attempts during an existing lockout period. This could inadvertently extend the lockout time indefinitely.
Install
-
pip install django-axes
Imports
- AxesStandaloneBackend
from axes.backends import AxesStandaloneBackend
- AxesMiddleware
from axes.middleware import AxesMiddleware
- axes.signals.user_locked_out
from django.dispatch import receiver from axes.signals import user_locked_out
- axes.decorators.axes_prevent_lockout
from axes.decorators import axes_prevent_lockout
Quickstart
# settings.py
INSTALLED_APPS = [
# ... other Django apps
'axes',
]
AUTHENTICATION_BACKENDS = [
'axes.backends.AxesStandaloneBackend', # Must be first
'django.contrib.auth.backends.ModelBackend',
]
MIDDLEWARE = [
# ... other Django middleware
'axes.middleware.AxesMiddleware', # Should be last if overriding auth response
]
# Optional: Basic configuration
AXES_FAILURE_LIMIT = 5
AXES_COOLOFF_TIME = 60 # In minutes or timedelta object (e.g., timedelta(minutes=30))
# AXES_LOCK_OUT_BY_IP_OR_USERNAME = True # Lock out by IP or username, not both
# Then, run migrations:
# python manage.py migrate
# And check your configuration:
# python manage.py check