Zakaj se prijave poddomene zlomijo v Django-Tenants: uganka iz resničnega sveta
Predstavljajte si, da zgradite aplikacijo Django z več najemniki, kjer vsaka poddomena služi drugemu najemniku, brezhibno integrira avtentikacijo uporabnikov. Vse se zdi popolno, dokler stran za prijavo na poddomeni ne vrže grozljivega . Praskate se po glavi in se sprašujete, zakaj prijava deluje brezhibno, prijava poddomene pa ne. 🤔
Ta težava je frustrirajoča, ker se zdi kot paradoks: sistem jasno prepozna uporabnike, saj se lahko prijavite v skrbniško ploščo. Ko ste prijavljeni, lahko dostopate do strani, specifičnih za najemnika, in celo uspešno oddate obrazce. Ko pa pritisnete stran za prijavo, se pojavi napaka: Kaj se v resnici dogaja pod pokrovom?
Naj povem primerljiv primer. Kot bi imeli dvoja vrata v hišo – ena za goste (vaša glavna domena) in ena za družino (poddomene). Vrata za goste delujejo dobro, družinska pa se zagozdijo. Veste, da so ključi pravilni, vendar je nekaj globlje narobe z mehanizmom zaklepanja – na primer nepričakovano neujemanje v poizvedbah sheme zbirke podatkov.
Koren težave je v tem, kako Django Rest Framework sodeluje z knjižnica. Natančneje, žetoni se poizvedujejo glede na namesto sheme najemnika, kar povzroči a ForeignKeyViolation napaka. Poglobimo se v to težavo, odkrijmo vzrok in popravimo prijavna vrata za vse vaše poddomene! 🔧
Ukaz | Primer uporabe |
---|---|
schema_context() | Omogoča preklapljanje med shemami v nastavitvi Django z več najemniki. Primer: s schema_context('ime_najemnika'): zagotavlja, da se operacije izvajajo v navedeni shemi baze podatkov najemnika. |
authenticate() | Preverja pristnost uporabnika z uporabo njegovih poverilnic. Primer: user = authenticate(request, username=uporabniško ime, password=password) preveri, ali so podane poverilnice veljavne. |
Token.objects.get_or_create() | Pridobi obstoječi žeton za uporabnika ali ga ustvari, če ne obstaja. Primer: žeton, ustvarjen = Token.objects.get_or_create(user=user). |
csrf_exempt | Onemogoči zaščito CSRF za določen pogled. Primer: @csrf_exempt se uporablja pri obravnavanju zunanjih ali nebrskalniških zahtev API. |
connection.tenant.schema_name | Pridobi ime sheme trenutnega najemnika v večnajemniški aplikaciji Django. Primer: ime_sheme_najemnika = ime_sheme_najemnika povezave. |
JsonResponse() | Vrne podatke v obliki JSON kot odziv HTTP. Primer: return JsonResponse({"status": "success", "token": token.key}). |
APIClient() | Odjemalec za testiranje ogrodja Django Rest Framework, ki omogoča simulacijo zahtev HTTP v testih. Primer: self.client = APIClient(). |
localStorage.setItem() | Shrani par ključ-vrednost v lokalno shrambo brskalnika. Primer: localStorage.setItem('token', data.token) shrani žeton za prihodnjo uporabo. |
Swal.fire() | Prikaže opozorilna pojavna okna z uporabo knjižnice SweetAlert2. Primer: Swal.fire({icon: 'error', title: 'Login Failed'}) prikazuje stilizirano sporočilo o napaki. |
TestCase | Uporablja se za pisanje testov enot v Djangu. Primer: razred TenantLoginTest(TestCase): ustvari testni razred za testiranje prijave, specifično za shemo. |
Obvladovanje avtentikacije, specifične za najemnika, v Django-Tenants
Zgornji skripti obravnavajo kritično težavo v aplikacijah Django z več najemniki, kjer se žetoni poizvedujejo iz namesto ustrezne sheme najemnika. Do tega vedenja pride, ker Django Rest Framework (DRF) ne preklopi samodejno shem pri interakciji z modeli žetonov. Da bi to rešili, izkoriščamo knjižnice metoda, ki nam omogoča eksplicitno izvajanje poizvedb baze podatkov znotraj pravilne sheme najemnika. To zagotavlja, da preverjanje pristnosti uporabnikov in pridobivanje žetonov deluje brezhibno za vsakega najemnika, ne glede na to, ali do njega dostopate prek primarne domene ali poddomen. Brez te prilagoditve pride do napake ForeignKeyViolation, ker sistem išče uporabniške zapise v napačni shemi.
Funkcija `dual_login_view` prikazuje, kako preveriti pristnost uporabnikov, hkrati pa zagotoviti, da povezava baze podatkov kaže na shemo najemnika. Najprej ekstrahira uporabniško ime in geslo iz tovora zahteve. Nato z uporabo metode `authenticate` potrdi poverilnice. Če je uspešen, prijavi uporabnika in ustvari žeton z uporabo metode `Token.objects.get_or_create()` DRF. Da bi zagotovili, da ta poizvedba cilja na pravilno shemo, funkcija `schema_context` ovije logiko in preklopi kontekst baze podatkov na aktivno shemo najemnika. To zagotavlja, da lahko sistem poišče pravilne zapise uporabnikov in žetonov, s čimer odpravi napako neujemanja sheme.
Razred `TenantAwareLoginAPIView` izboljša rešitev s sprejetjem APIView ogrodja Django Rest Framework za modularni pristop. Sprejme zahteve POST, ki vsebujejo uporabniške poverilnice, jih potrdi z uporabo `authenticate` in ustvari žeton, če so poverilnice pravilne. Pomembno je, da uporablja `schema_context` za izvajanje vseh operacij znotraj pravilne sheme najemnika. Ta pogled, ki temelji na razredu, je idealen za sodobne implementacije API-jev, ker centralizira obravnavo napak in zagotavlja čiste, strukturirane odgovore. Na primer, vrnitev žetona JSON zagotavlja, da ga sprednji del lahko shrani v lokalno shrambo in uporabi za nadaljnje overjene zahteve.
Na sprednjem delu ima skript za oddajo obrazca JavaScript ključno vlogo pri izdelavi varnih in strukturiranih zahtev končni točki za prijavo. Prepreči privzeto vedenje obrazca, potrdi vnosna polja in pošlje poverilnice skupaj z žetonom CSRF prek zahteve API-ja za pridobivanje. Po prejemu uspešnega odgovora se žeton shrani v `localStorage` in uporabnik je preusmerjen. Če strežnik vrne napako, knjižnica SweetAlert2 prikaže prijazno opozorilo. To naredi uporabniško izkušnjo bolj gladko in zagotovi ustrezne povratne informacije o napakah. Na primer, pri dostopu do poddomene najemnika bi uporabnik, ki se prijavi z veljavnimi poverilnicami, takoj videl sporočilo o uspehu in bil preusmerjen na nadzorno ploščo aplikacije. 🔒
Obravnavanje težav s prijavo v poddomeno v Django-Tenants z optimiziranimi poizvedbami sheme
Zaledna rešitev, ki uporablja Django ORM z eksplicitno izbiro sheme in obravnavanjem napak.
# Import necessary libraries
from django.db import connection
from rest_framework.authtoken.models import Token
from django.contrib.auth import authenticate, login
from django.http import JsonResponse
from django_tenants.utils import schema_context
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def dual_login_view(request):
"""Handle login for multi-tenant subdomains with correct schema."""
if request.method == "POST":
username = request.POST.get("login")
password = request.POST.get("password")
tenant_schema_name = connection.tenant.schema_name
try:
# Switch to the correct tenant schema
with schema_context(tenant_schema_name):
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Generate or retrieve token
token, created = Token.objects.get_or_create(user=user)
return JsonResponse({"status": "success", "token": token.key})
else:
return JsonResponse({"status": "error", "message": "Invalid credentials"}, status=400)
except Exception as e:
return JsonResponse({"status": "error", "message": str(e)}, status=500)
return JsonResponse({"status": "error", "message": "Invalid request method"}, status=405)
Eksplicitno upravljanje žetonov z uporabo shem, ki podpirajo najemnike
Modulariziran pogled Django API za večkratno uporabo za prijavo v arhitekturi z več najemniki.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth import authenticate
from rest_framework.authtoken.models import Token
from django_tenants.utils import schema_context
class TenantAwareLoginAPIView(APIView):
"""Login endpoint that ensures tenant-aware schema handling."""
def post(self, request):
username = request.data.get("username")
password = request.data.get("password")
tenant_schema_name = request.tenant.schema_name
if not username or not password:
return Response({"error": "Username and password required"}, status=status.HTTP_400_BAD_REQUEST)
try:
with schema_context(tenant_schema_name):
user = authenticate(request, username=username, password=password)
if user is None:
return Response({"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED)
# Generate or retrieve token for the user
token, created = Token.objects.get_or_create(user=user)
return Response({"token": f"Token {token.key}"}, status=status.HTTP_200_OK)
except Exception as e:
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Frontend skript za obravnavanje zahtev za prijavo poddomene
Rešitev JavaScript za obdelavo oddaje obrazca in obdelavo prijave na podlagi žetonov za poddomene najemnikov.
<script>
document.querySelector('form').addEventListener('submit', function(event) {
event.preventDefault();
let form = event.target;
let formData = new FormData(form);
fetch("{% url 'tenant_aware_login' %}", {
method: 'POST',
body: JSON.stringify(Object.fromEntries(formData)),
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': formData.get('csrfmiddlewaretoken')
}
})
.then(response => {
if (!response.ok) throw new Error('Server Error');
return response.json();
})
.then(data => {
if (data.token) {
localStorage.setItem('token', data.token);
window.location.href = '/';
} else {
Swal.fire({
icon: 'error',
title: 'Login Failed',
text: data.error || 'Invalid credentials'
});
}
})
.catch(error => {
console.error('Error:', error);
});
});
</script>
Preizkus enote za preverjanje pristnosti žetona, ki upošteva shemo
Preskus enote v Pythonu, da zagotovite, da API pravilno obravnava preklapljanje sheme.
from django.test import TestCase
from rest_framework.test import APIClient
from django_tenants.utils import schema_context
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
class TenantLoginTest(TestCase):
def setUp(self):
self.client = APIClient()
with schema_context('test_tenant'): # Switch to tenant schema
self.user = User.objects.create_user(username='testuser', password='testpass')
def test_successful_login(self):
with schema_context('test_tenant'):
response = self.client.post('/api/login/', {
'username': 'testuser',
'password': 'testpass'
})
self.assertEqual(response.status_code, 200)
self.assertIn('token', response.json())
def test_invalid_login(self):
with schema_context('test_tenant'):
response = self.client.post('/api/login/', {
'username': 'wronguser',
'password': 'wrongpass'
})
self.assertEqual(response.status_code, 401)
self.assertIn('error', response.json())
Razumevanje vloge poizvedb po žetonih, specifičnih za najemnika, v aplikacijah Django z več najemniki
Eden glavnih vidikov zagotavlja, da se operacije baze podatkov vedno izvajajo znotraj pravilne sheme najemnika. Težava v tem primeru se zgodi, ker Djangovo privzeto vedenje predpostavlja eno shemo v skupni rabi, kar vodi do napak, ko žetonov ali uporabnikov ni mogoče najti v . Z uporabo orodij, kot je funkcijo od django-najemniki knjižnici izrecno preklapljamo med shemami za izvajanje poizvedb, specifičnih za najemnika. To zagotavlja, da so poizvedbe za preverjanje pristnosti za uporabnike in žetone usmerjene v pravilno shemo.
Druga ključna podrobnost, ki je pogosto spregledana, je, kako deluje. Privzeto išče uporabniške zapise v aktivni shemi baze podatkov. Če je trenutna shema nepravilna, poizvedba ne uspe z a napaka. Da bi to odpravili, zagotovimo, da se vsaka poizvedba, ki vključuje model žetona, izvede v ustreznem kontekstu sheme najemnika. Brez te prilagoditve tudi veljavni uporabniki ne bodo mogli preveriti pristnosti, ker ID-ja uporabnika ni mogoče najti v privzeti shemi.
Poleg tega ima sprednja koda ključno vlogo pri učinkoviti komunikaciji s temi zalednimi procesi. Zagotavljanje, da API za pridobivanje pošlje in pravilno obravnava odgovore JSON je ključnega pomena. Na primer, zavijanje klicev API-ja v bloke try-catch in obravnavanje napak z uporabo uporabniku prijaznih knjižnic, kot je izboljša uporabnost. Te izboljšave zagotavljajo, da potek prijave ostane nemoten, tudi ko preklapljate med poddomenami ali naletite na napake, specifične za shemo. Predstavljajte si na primer platformo SaaS, kjer vsako podjetje (najemnik) uporablja poddomeno – popravljanje konteksta sheme zagotavlja, da se vsak zaposleni nemoteno prijavi brez motenj. 🚀
- Kaj povzroča a med prijavo?
- Napaka nastane zaradi poizveduje po napačni shemi, kar povzroči neujemanje pri iskanju uporabniških zapisov.
- Kako zagotovim, da poizvedbe žetonov kažejo na pravilno shemo najemnika?
- Uporaba od knjižnico, da zavijete izvedbo poizvedbe in preklopite na pravilno shemo.
- Zakaj prijava v skrbniško ploščo deluje, prijava uporabnika pa ne uspe?
- Skrbnik Django samodejno prilagodi kontekste sheme, vendar poglede po meri uporablja oz morda ne, razen če ni izrecno konfigurirano.
- Kako pridobim in shranim prijavni žeton na sprednji strani?
- Uporabite API za pridobitev za pošiljanje poverilnic, nato shranite žeton odziva z uporabo za trajno avtentikacijo.
- Kako lahko bolje prikažem sporočila o napakah za neuspele prijave?
- Implementirajte sprednja opozorila z uporabo knjižnic, kot je za obveščanje uporabnikov o nepravilnih poverilnicah ali težavah s strežnikom.
Razreševanje napak pri prijavi v aplikacijah Django z več najemniki zahteva zagotovitev, da vse poizvedbe baze podatkov delujejo v pravilni shemi. Z eksplicitno uporabo orodij, kot je kontekst sheme, lahko zagotovimo, da so uporabniški žetoni pridobljeni iz pravilne baze podatkov najemnika, s čimer se izognemo konfliktom shem.
Predstavljajte si, da delate na platformi SaaS, kjer se uporabniki soočajo z napakami pri prijavi samo na poddomenah. S pravilnim preklopom sheme so te težave odpravljene, kar zagotavlja brezhibno preverjanje pristnosti. Sprejetje tega popravka ne le izboljša ampak tudi zagotavlja varen in učinkovit dostop do podatkov za vsakega najemnika. 🔧
- Podrobna dokumentacija o knjižnica, ki razlaga upravljanje shem v aplikacijah z več najemniki. Na voljo na: Dokumentacija Django-Tenants .
- Uradna dokumentacija Django Rest Framework (DRF) o preverjanju pristnosti žetonov. Več o tem na: Preverjanje pristnosti žetona DRF .
- Obsežen vodnik o uporabi schema_context v okoljih z več najemniki. Najdeno na: GitHub – najemniki Django .
- Vpogled v ravnanje z žetoni CSRF v aplikacijah Django: Dokumentacija Django CSRF .
- Najboljše prakse za oblikovanje platform SaaS z več najemniki, vključno s preverjanjem pristnosti uporabnikov: SaaS Pegasus Vodič za več najemnikov .