python / expert
Snippet
Django Authentication Backend mit Custom User Model
Django's Authentifizierungssystem ist erweiterbar via Authentication Backends, die mehrere Authentifizierungsmethoden gleichzeitig unterstützen können. Dieses Snippet demonstriert ein Custom Authentication Backend, das gegen Username, Email oder Telefonnummer authentifiziert, Account-Sperre nach fehlgeschlagenen Versuchen implementiert und Django's F() Expressions für atomare Zähler-Updates verwendet. Kombiniert mit einem Custom User Model Manager bietet dies eine vollständige Authentifizierungslösung mit Security-Hardening.
snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from django.contrib.auth.backends import ModelBackendfrom django.contrib.auth import get_user_modelfrom django.db.models import Qclass MultipleAuthBackend(ModelBackend):def authenticate(self, request, username=None, password=None, **kwargs):User = get_user_model()if not username or not password:return Nonetry:user = User.objects.get(Q(username=username) | Q(email=username) | Q(phone=username))except User.DoesNotExist:User().set_password(password)return Noneif not user.is_active:return Noneif user.locked_until and user.locked_until > now():raise PermissionError('Account temporarily locked')if user.check_password(password):self._update_login_attempts(user, success=True)return userself._update_login_attempts(user, success=False)return Nonedef _update_login_attempts(self, user, success=True):if success:user.failed_login_attempts = 0user.locked_until = Noneelse:user.failed_login_attempts = F('failed_login_attempts') + 1if user.failed_login_attempts >= getattr(settings, 'MAX_LOGIN_ATTEMPTS', 5):user.locked_until = now() + timedelta(minutes=30)user.save(update_fields=['failed_login_attempts', 'locked_until'])class CustomUserManager(BaseUserManager):def create_superuser(self, username, email, password, **extra_fields):extra_fields.setdefault('is_staff', True)extra_fields.setdefault('is_superuser', True)if extra_fields.get('is_staff') is not True:raise ValueError('Superuser must have is_staff=True')return self._create_user(username, email, password, **extra_fields)def _create_user(self, username, email, password, **extra_fields):if not username:raise ValueError('Username must be set')
django
Erklärung
1
class MultipleAuthBackend(ModelBackend):
Custom Backend erweitert Django's ModelBackend für Multi-Feld-Authentifizierung
2
Q(username=username) | Q(email=username) | Q(phone=username)
Q Objects kombinieren OR-Bedingungen für Authentifizierung mit beliebigem Identifier
3
if not user.is_active: return None
Verhindert Authentifizierung von inaktiven/deaktivierten Accounts
4
user.locked_until and user.locked_until > now()
Zeitbasierte Account-Sperre nach fehlgeschlagenen Versuchen
5
user.failed_login_attempts = F('failed_login_attempts') + 1
F() Expression ermöglicht atomares Datenbank-seitiges Inkrement ohne Race Conditions
6
user.save(update_fields=[...])
Partielles Update beschränkt SQL auf nur geänderte Spalten für Effizienz