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 Common errors
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.
Warnings
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.
Imports
- watch_login
from defender.decorators import watch_login - is_already_locked
from defender import is_already_locked - unlock
from defender import unlock
Quickstart
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