from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
User = get_user_model()
class EmailBackend(ModelBackend):
"""Authenticate using email instead of username."""
def authenticate(self, request, username=None, password=None, **kwargs):
# username parameter contains email
try:
user = User.objects.get(email=username)
except User.DoesNotExist:
return None
if user.check_password(password) and self.user_can_authenticate(user):
return user
return None
class TokenBackend(ModelBackend):
"""Authenticate using API token."""
def authenticate(self, request, token=None, **kwargs):
if not token:
return None
try:
from api.models import ApiToken
api_token = ApiToken.objects.select_related('user').get(
key=token,
is_active=True
)
return api_token.user
except ApiToken.DoesNotExist:
return None
AUTHENTICATION_BACKENDS = [
'accounts.backends.EmailBackend',
'accounts.backends.TokenBackend',
'django.contrib.auth.backends.ModelBackend', # Fallback
]
Custom auth backends enable alternative authentication methods. I subclass ModelBackend and override authenticate(). Common use cases include email login, LDAP, OAuth, or custom token auth. The backend returns a user object or None. I add it to AUTHENTICATION_BACKENDS in settings. Multiple backends can coexist—Django tries each in order. For permissions, I override get_user_permissions() and get_group_permissions(). This extends authentication beyond username/password without replacing Django's auth system.