Django Defender

raw JSON →
0.9.8 verified Mon Apr 27 auth: no python

Redis-based Django app that locks out users after too many failed login attempts. Current version 0.9.8, requires Python ~=3.7 and Django >=3.2 (or 4.x). Maintained by Jazzband. Release cadence: irregular, last release Jan 2024.

pip install django-defender
error AttributeError: module 'defender' has no attribute 'watch_login'
cause Trying to import watch_login directly from the defender package instead of the decorators submodule.
fix
Use 'from defender.decorators import watch_login' instead.
error ConnectionError: Error 111 connecting to localhost:6379. Connection refused.
cause Redis server is not running or not reachable at the configured URL.
fix
Start Redis or set DEFENDER_REDIS_URL to the correct Redis URL.
error django.core.exceptions.ImproperlyConfigured: The DEFENDER_REDIS_URL setting must not be empty.
cause DEFENDER_REDIS_URL is not set in Django settings.
fix
Add 'DEFENDER_REDIS_URL = os.environ.get('DEFENDER_REDIS_URL', 'redis://localhost:6379/0')' to settings.py.
breaking django-defender requires a running Redis server. Without it, login attempts will fail silently or raise a ConnectionError.
fix Ensure Redis is running and DEFENDER_REDIS_URL is correctly configured.
gotcha The default COOLOFF_TIME is 300 seconds (5 minutes). After that, the counter resets. This can be confusing if you expect lockout to persist longer.
fix Set DEFENDER_COOLOFF_TIME (or DEFENDER_ATTEMPT_COOLOFF_TIME / DEFENDER_LOCKOUT_COOLOFF_TIME from v0.9.6) to your desired value in seconds.
gotcha watch_login decorator expects the request object to have a user attribute. If used on a custom login view that doesn't set request.user, it will raise AttributeError.
fix Ensure the view sets request.user before calling watch_login, or use the middleware instead.
deprecated Python 3.6 and Django 3.1 support dropped in v0.9.2. Django 2.2 dropped in v0.9.3.
fix Upgrade to Python >=3.7 and Django >=3.2.

Basic setup: add 'defender' to INSTALLED_APPS, configure REDIS_URL, add FailedLoginMiddleware, include defender URLs.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'defender',
]

# settings.py
DEFENDER_REDIS_URL = os.environ.get('DEFENDER_REDIS_URL', 'redis://localhost:6379/0')

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'defender.middleware.FailedLoginMiddleware',
]

# Add to urlpatterns in urls.py
from defender import urls as defender_urls
urlpatterns += [
    path('defender/', include(defender_urls)),
]

# run migrations
# python manage.py migrate defender