Djangon'daki Fabrika Yöntemi Deseniyle Modüler Kimlik Sistemi Tasarlamak
Modern web uygulamaları hem esnek hem de ölçeklenebilir olan kimlik doğrulama sistemleri talep eder. Kullanıcılar e-posta ve şifre kullanarak giriş yapmayı bekler, sosyal hesaplar, tek işaret-on (SSO) protokolleri veya token tabanlı yöntemler, çoğu zaman aynı uygulama içinde aynı şekilde tasarlanmıştır. Django'nun yerleşik kimlik doğrulama sistemi, kullanıcı seçimi veya istek parametreleri gibi birçok gerileme faktörü destekler.
Bu sınırlamaların üstesinden gelmek için birçok geliştirici, müşteri koduna beton sınıflara uyum sağlamadan önce sistemi tasarlar.Bu makalede, Django'da bir modüler sistem nasıl kullanılacağını öğreneceksiniz, gerçek dünya örnekleri ve en iyi uygulamalarla tamamlanacaktır.
Fabrika Yönteminin arkasındaki temel kavramları inceleyeceğiz, birkaç ortak strateji için beton kimlik doğrulama sınıfları inşa edeceğiz (kullanıcı/password, OAuth2, JWT ve sosyal giriş), ve uygun geri dönüşleri giriş veya yapılandırmaya dayanan bir fabrika inşa edeceğiz.Sonunda, kodbazınızın geri kalanını korumak için önemsiz hale getirir.
Fabrika Yönteminin Anlayışı
Fabrika Yöntemi modeli bir nesne oluşturmak için bir arayüz tanımlar, ancak alt sınıfların hangi sınıfın anında karar vermesine izin verir. Bu, yaratılış tasarım desenleri kategorisine ait ve özellikle bir sınıf oluşturmak için gereken nesneleri tahmin edemez veya yarattığı nesnelere göre daha fazla fayda sağlar.
Kontrol bağlamında, desen, tüm kimlik doğrulama yöntemlerine (örneğin, açık / Kısa Prensipleri) dayanan bir fabrika sınıfına karar vermenizi sağlar ve ardından mevcut kodu herhangi bir beton sınıfını değiştirmeden önce yeni doğrulama yöntemleri tanıtabilirsiniz.
Fabrika Yöntemi Basit bir Fabrikadan farklıdır (bir sınıfı seçen statik bir yöntem) genellikle oluşturulan nesneye göre alt sınıflara dayanır. Ancak, Python ve Django'da, uygun bir alt sınıf döndürürseniz statik bir fabrika yöntemi genellikle yeterlidir ve daha temizdir, çünkü aşağıda bir Fabrika Yöntemi veya statik bir Fabrika çağırın, beton sınıflardan gelen istemci kodun faydaları aynı kalır.
Desenin daha derin bir açıklaması için, Guru'nun Fabrika Yöntemi kılavuzunu yeniden belirtmek için bakınız[Dönetici: 1).
Deseni Django'da Uygulamayın
Henüz üretim hazırlı kimlik doğrulama modülü inşa ederek başlayacağız. Proje yapısı buna benzeyebilir:
myproject/
authfactory/
__init__.py
base_auth.py
backends.py
factory.py
views.py
templates/
settings.py
Özet Kimlik Sınıfı
Her beton geri dönüşünün arayüzünü tanımlayan soyut bir temel sınıf oluşturun. Bu arayüz en az bir anİLFLT:3) yöntemi içerecektir, ancak aynı zamanda posta işlemi için opsiyonel kancalar da ekleyebilirsiniz.
# authfactory/base_auth.py
from abc import ABC, abstractmethod
class BaseAuthMethod(ABC):
"""Common interface for all authentication strategies."""
@abstractmethod
def authenticate(self, request):
"""
Authenticate the user from the given request.
Must return a User instance on success, or None on failure.
"""
pass
def get_user(self, user_id):
"""
Optional method to retrieve a user object by ID.
Can be used by backends that support session restoration.
"""
return None
[[DÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜŞÜNÜŞÜŞÜNÜŞÜNÜŞÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜŞÜNÜŞ
Beton Açıklama Geri Döndü
Şimdi en yaygın kimlik doğrulama yöntemleri için beton sınıfları uygulayın. şunları içerecek:
- Kullanıcı adı/password doğrulama ( Django'nun inşa edilmiş-inurFLT:9)
- OAuth2 doğrulama (abstract örneği)
- JSON Web Hediyesi (JWT) API müşterileri için doğrulama
- Django-allauth aracılığıyla sosyal giriş
Username/Password Backend
Bu, Django'nun kendi kimlik doğrulama sistemine geri döner, ki bu savaş test edilir ve şifrenin devrilmesi, throttling ve diğer güvenlik özellikleri içerir.
# authfactory/backends.py
from django.contrib.auth import authenticate
from .base_auth import BaseAuthMethod
class UsernamePasswordAuth(BaseAuthMethod):
def authenticate(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
return authenticate(request, username=username, password=password)
def get_user(self, user_id):
from django.contrib.auth import get_user_model
User = get_user_model()
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
OAuth2 Backend
OAuth2 akışları daha karmaşıktır. Bu örnek, üçüncü taraf bir sağlayıcıdan alınan bir erişimin nasıl doğrulandığını gösterir.
# authfactory/backends.py (continued)
import requests
from django.contrib.auth import get_user_model
from .base_auth import BaseAuthMethod
class OAuth2Auth(BaseAuthMethod):
def __init__(self, provider_token_url, userinfo_url, client_id):
self.provider_token_url = provider_token_url
self.userinfo_url = userinfo_url
self.client_id = client_id
def authenticate(self, request):
access_token = request.POST.get('access_token') or \
request.META.get('HTTP_AUTHORIZATION', '').replace('Bearer ', '')
if not access_token:
return None
# Verify token with the provider's introspection endpoint (simplified)
response = requests.get(
self.userinfo_url,
headers={'Authorization': f'Bearer {access_token}'}
)
if response.status_code != 200:
return None
user_info = response.json()
email = user_info.get('email')
if not email:
return None
User = get_user_model()
user, _ = User.objects.get_or_create(
email=email,
defaults={'username': email.split('@')[0]}
)
return user
def get_user(self, user_id):
User = get_user_model()
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
OAuth2 backends'in ayrıca imzayı, çek expiry'yi doğrulaması ve muhtemelen doğrulayınca, sağlam bir uygulama, “Ücretsiz” veya “FLT:14 gibi bir kütüphane kullanır.
JWT Backend ( REST API için)
Django REST Framework (DRF) ile bir API inşa ederken, genellikle JSON Web Tokens aracılığıyla kullanıcıları kimliklendirmeniz gerekir. Aşağıdaki geri dönüş bir JWT'yi doğrular ve kullanıcıyı ödeme yükünden alır.
# authfactory/backends.py (continued)
import jwt
from django.conf import settings
from django.contrib.auth import get_user_model
from .base_auth import BaseAuthMethod
class JWTAuth(BaseAuthMethod):
def __init__(self, secret_key=None, algorithm='HS256'):
self.secret_key = secret_key or settings.SECRET_KEY
self.algorithm = algorithm
def authenticate(self, request):
token = request.META.get('HTTP_AUTHORIZATION', '').replace('Bearer ', '')
if not token:
return None
try:
payload = jwt.decode(
token,
self.secret_key,
algorithms=[self.algorithm]
)
except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
return None
user_id = payload.get('user_id')
if not user_id:
return None
User = get_user_model()
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
def get_user(self, user_id):
User = get_user_model()
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Sosyal Giriş django-allauth
Sosyal kimlik doğrulama için [[ŞUYGÜŞÜNÜSÜŞÜNÜSÜŞÜNÜSÜSÜŞÜNÜŞÜNÜSÜSÜSÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞ
# authfactory/backends.py (continued)
from allauth.socialaccount.models import SocialLogin, SocialAccount
from django.contrib.auth import get_user_model
from .base_auth import BaseAuthMethod
class SocialAuthBackend(BaseAuthMethod):
def __init__(self, provider):
self.provider = provider
def authenticate(self, request):
# This is called after allauth's social login process.
# The user object is typically stored in the request by allauth.
if hasattr(request, 'user') and request.user.is_authenticated:
return request.user
# Alternatively, you could inspect the session for a social token.
return None
def get_user(self, user_id):
User = get_user_model()
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Bu geri dönüş kasıtlı olarak basittir; tam bir entegrasyon, tümauth tarafından yönetilen sosyal giriş devlet makinesini idare eder. anahtar nokta, her geri dönüş aynıFLT:18'e uygun olmasıdır.
Fabrika Sınıfı
Fabrika sınıfı hangi betonu anlık olarak geri döndüreceğine karar verir. Basit bir şekilde kullanılabilirlik için basit bir şekilde bir sözlük haritası veya bir sözlük haritası da Django ayarlarından yapılandırmaya izin veririz.
# authfactory/factory.py
from django.conf import settings
from .backends import (
UsernamePasswordAuth,
OAuth2Auth,
JWTAuth,
SocialAuthBackend,
)
class AuthMethodFactory:
"""Factory that returns the appropriate authentication backend."""
_backends = {
'username_password': UsernamePasswordAuth,
'oauth2': lambda: OAuth2Auth(
provider_token_url=settings.OAUTH2_TOKEN_URL,
userinfo_url=settings.OAUTH2_USERINFO_URL,
client_id=settings.OAUTH2_CLIENT_ID,
),
'jwt': lambda: JWTAuth(
secret_key=settings.JWT_SECRET_KEY,
algorithm=settings.JWT_ALGORITHM,
),
'social': lambda: SocialAuthBackend(provider='google'),
}
@classmethod
def get_backend(cls, method_type, **kwargs):
"""
Return an instance of the authentication backend
identified by `method_type`.
"""
if method_type not in cls._backends:
raise ValueError(f"Unknown authentication method: {method_type}")
backend_creator = cls._backends[method_type]
if callable(backend_creator):
return backend_creator()
return backend_creator()
@classmethod
def get_backend_names(cls):
"""Return a list of all registered backend names."""
return list(cls._backends.keys())
Bu uygulama, belirli bir istek için aşırı varsayılan parametreleri kabul edebilir (örneğin, farklı bir sağlayıcı).
Daha da büyük esneklik için, veritabanındaki arka uç konfigürasyonunu saklayabilirsiniz ve dinamik olarak kayıt olabilirsiniz. Ancak, statik bir haritalama genellikle test etmek için yeterlidir ve daha kolaydır.
Görüntüleme ve Ortaware'deki Fabrikayı kullanarak
Şimdi fabrikayı Django görüşlerinize entegre edin. Müşteriye (veya API tüketicisi), hangi kimlik doğrulama yönteminin kullanılması gerektiğini söylemek gerekir. Bu, bir sorgu parametresi, POST alanı veya özel bir HTTP başlığıyla yapılabilir.
Geleneksel Login View
# authfactory/views.py
from django.contrib.auth import login
from django.http import HttpResponse, Http404
from django.views.decorators.csrf import csrf_exempt
import json
from .factory import AuthMethodFactory
@csrf_exempt
def login_view(request):
"""
Login endpoint that supports multiple authentication methods.
Expects a JSON body with 'auth_type' and method-specific credentials.
"""
if request.method != 'POST':
return HttpResponse(status=405, content='Method not allowed')
try:
data = json.loads(request.body)
except json.JSONDecodeError:
return HttpResponse(status=400, content='Invalid JSON')
auth_type = data.get('auth_type', 'username_password')
try:
backend = AuthMethodFactory.get_backend(auth_type)
except ValueError as e:
return HttpResponse(status=400, content=str(e))
user = backend.authenticate(request)
if user is not None:
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
return HttpResponse('Login successful')
else:
return HttpResponse(status=401, content='Invalid credentials')
Not: TheFLETHT:23) işlevi, gerçek bir uygulamada, her fabrikayı oturumda geri doğrulama yoluna ya da otomatik olarak elde etmek için fabrikanın arka uç sınıfını kullanabilirsiniz.Polikit için, burada sertcodedFLT:24; üretimde, her fabrikayı tekrar Django arka uç dizesine geri döndürebilirsin.
Django REST Framework ile API Görüntüleme
Bir API'yi açığa çıkarırsanız, DRF'nin kimlik doğrulama sınıflarıyla kullanım için fabrika modelini adapte edebilirsiniz. ayrı bir görüş oluşturmak yerine, fabrikaya delege eden özel bir kimlik doğrulama sınıfı yazabilirsiniz.
# authfactory/rest_auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .factory import AuthMethodFactory
class FactoryBackendAuth(BaseAuthentication):
"""
DRF authentication class that uses the AuthMethodFactory
to validate tokens. The 'auth_type' is derived from a custom
header 'X-Auth-Type'.
"""
def authenticate(self, request):
auth_type = request.META.get('HTTP_X_AUTH_TYPE', 'jwt')
try:
backend = AuthMethodFactory.get_backend(auth_type)
except ValueError:
raise AuthenticationFailed('Unsupported authentication type')
user = backend.authenticate(request)
if user is None:
raise AuthenticationFailed('Invalid token')
return (user, None)
def authenticate_header(self, request):
return 'Bearer' # Generic challenge for any method
Sonra bu doğrulama sınıfı DRF ayarlarınıza veya görüşlerinize ekleyin:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'authfactory.rest_auth.FactoryBackendAuth',
# other classes can be kept as fallback
],
}
Otomatik Backend Selection için Ortaware
Bazen istek özelliklerine göre otomatik olarak geri dönüş seçmeniz gerekir (örneğin, kullanıcı ajanı, IP, domain). Talepleri sarmak ve uygun geri dönüşleri 444FLT:27) enjekte edebilirsiniz.
# authfactory/middleware.py
from .factory import AuthMethodFactory
class AutoAuthBackendMiddleware:
"""
Middleware that selects an authentication backend based on
the request path or host.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Decide on auth type - example: use 'oauth2' for /api/v2/auth/*
path = request.path_info
if path.startswith('/api/v2/auth/'):
request.auth_type = 'oauth2'
elif path.startswith('/api/v1/auth/'):
request.auth_type = 'jwt'
else:
request.auth_type = 'username_password'
return self.get_response(request)
Daha sonra, istemcinin bunu belirtmesini gerektirmeden görüşlerinizde İZFLT:29 kullanabilirsiniz.
Gelişmiş Tahminler
Logging ve Hata
Üretim doğrulama sistemleri sağlam bir oturuma ihtiyaç duyar. Her bir arka uçta yapısal bir giriş ekleyin ve doğrulama girişimleri, başarısızlıklar ve potansiyel güvenlik olayları yakalamak için fabrikayı ekleyin.
import logging
logger = logging.getLogger(__name__)
class JWTAuth(BaseAuthMethod):
def authenticate(self, request):
# ... validation ...
if not token:
logger.warning('JWT auth attempted with no token')
return None
try:
payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
except jwt.ExpiredSignatureError:
logger.info('Expired JWT token')
return None
except jwt.InvalidTokenError:
logger.warning('Invalid JWT token')
return None
# ... user retrieval ...
if user is None:
logger.error(f'JWT valid but user {payload.get("user_id")} not found')
return user
Fabrikayı ve Backends test edin
Her bir geri dönüş izolasyonda test edilmelidir. Django'nun test müşterisini veya alaycı istekleri kullanın. Fabrika için, her kayıtlı yöntem için doğru türü geri döndürür ve bilinmeyenler için [[Şampücretsizler için) yükseltilir.
# tests/test_auth.py
from django.test import TestCase
from unittest.mock import Mock
from authfactory.factory import AuthMethodFactory
from authfactory.backends import UsernamePasswordAuth, OAuth2Auth
class FactoryTest(TestCase):
def test_get_username_password_backend(self):
backend = AuthMethodFactory.get_backend('username_password')
self.assertIsInstance(backend, UsernamePasswordAuth)
def test_get_oauth2_backend(self):
backend = AuthMethodFactory.get_backend('oauth2')
self.assertIsInstance(backend, OAuth2Auth)
def test_unknown_method_raises_error(self):
with self.assertRaises(ValueError):
AuthMethodFactory.get_backend('unknown')
class UsernamePasswordAuthTest(TestCase):
def test_authenticate_with_valid_credentials(self):
# Create a test user
from django.contrib.auth import get_user_model
User = get_user_model()
user = User.objects.create_user(username='test', password='secret')
# ... mock request ...
request = Mock()
request.POST = {'username': 'test', 'password': 'secret'}
backend = UsernamePasswordAuth()
result = backend.authenticate(request)
self.assertEqual(result, user)
Sistemin genişletilmesi
Yeni bir doğrulama yöntemi eklemek için (örneğin, SAML, sihirli bağlantı, WebAuthn), sadece ihtiyacınız var:
- [FONTD: 9) Yeni bir sınıf oluşturun ve bunu uygulayın.
- Bunu, ÂFFT:35'te sözlüğe kayıt edin.
- Seçmeli olarak Django ayarlarında bir yapılandırma girişi ekleyin.
Bu minimum ayak izi sistemi korumak ve test etmek için kolaylaştırır. Ayrıca her bir geri dönüş ayrı bir reusable uygulama olarak da paketleyebilirsiniz.
Fabrika Yöntemi Desenini Gerçekleştirmenin Faydaları
- [FONT:0)Modularity:[[Dönetici:[Dönetici: 0) Her kimlik doğrulama yöntemi kendi sınıfında düzenlenir ve bu kod tabanını gezinmek ve neden daha kolay hale getirmek.
- [FONT:0)Scalability:[Dönetici:[Dönetici:0) Yeni bir doğrulama stratejisi eklemek mevcut görüşlere, URL'lere veya iş mantığına değişiklikler gerektirmez.
- [FONT:0) Açık / Kısa Prens:[[Dönlendirme): Ana kimlik doğrulama altyapısı, yeni arka sınıflarla uzatma için kapalıdır.
- [FONT:0)Testability:[Döneticiler bağımsız olarak birim test edilebilir. Fabrikayı kullanarak gerçek kimlik doğrulama bağımlılıkları olmadan görüş test etmenizi sağlar.
- [[Dönetici:0)Configurability: [Dönetici: [Dönetici: 1) Fabrika ayarları, veritabanı kayıtları veya runtime parametreleri tarafından yönlendirilebilir, farklı dağıtım ortamları farklı kimlik doğrulama yöntemlerine izin verebilir.
- [FONT:0) ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç
Django'daki Fabrika Yöntemi modeli ile modüler bir kimlik doğrulama sistemi tasarlayın geleneksel olarak monolithic bir altyapı parçası esnek, extensible bileşenine dönüştürür.Her bir kimlik doğrulama stratejisi için soyut bir arayüz ve beton geri dönüşler belirleyerek, uygulamanızın geri kalanına dokunmadan kimlik doğrulama yöntemleri getirebilme yeteneği kazanırsınız. Fabrika sınıfı merkezileştirme mantığı ve desen Django'nun mevcut kimlik doğrulama çerçevesi, DRF ve üçüncü taraf kütüphaneleri ile sorunsuz bir şekilde bütünleştirir.
Bu yaklaşım doğrulama ile sınırlı değildir; aynı Fabrika Yöntemi modeli, ödeme ağ geçidi, bildirim kanalları veya veri ithalatçıları gibi Django projesinizin diğer bölgelerine uygulanabilir. Uygulamanız büyüdükçe, modeliniz temiz sınırları sürdürmenize yardımcı olur ve kodbase'inizi gelecekteki gereksinimlerinize uygun tutar.
Django'daki en iyi uygulamaları doğrulamayı daha iyi okumak için, DRF için kılavuzluk (DPMT) ve daha derin tasarım kalıplarına kılavuzluk etmek için, Guru'nun Fabrika Yöntemi açıklaması) mükemmel bir kaynaktır.