Menyelesaikan Kesalahan Masuk Subdomain Django-Tenant dengan Token Rest Framework

Menyelesaikan Kesalahan Masuk Subdomain Django-Tenant dengan Token Rest Framework
Menyelesaikan Kesalahan Masuk Subdomain Django-Tenant dengan Token Rest Framework

Mengapa Login Subdomain Rusak di Django-Tenants: Teka-teki Dunia Nyata

Bayangkan membangun aplikasi Django multi-penyewa di mana setiap subdomain melayani penyewa yang berbeda, dengan lancar mengintegrasikan otentikasi pengguna. Segalanya tampak sempurna—sampai halaman login pada subdomain menimbulkan ketakutan 500 Kesalahan Server Internal. Anda menggaruk kepala, bertanya-tanya mengapa domain utama login berfungsi dengan sempurna, tetapi login subdomain tidak. đŸ€”

Masalah ini membuat frustrasi karena terasa seperti sebuah paradoks: sistem mengenali pengguna dengan jelas karena Anda dapat masuk ke panel admin. Setelah masuk, Anda dapat mengakses halaman khusus penyewa dan bahkan berhasil mengirimkan formulir. Namun, ketika Anda membuka halaman login, muncul kesalahan: "Token tak terduga ' Apa yang sebenarnya terjadi?

Izinkan saya membagikan contoh yang relevan. Ini seperti memiliki dua pintu dalam sebuah rumah—satu untuk tamu (domain utama Anda) dan satu lagi untuk keluarga (subdomain). Pintu tamu berfungsi dengan baik, namun pintu keluarga macet. Anda tahu kuncinya benar, tetapi ada yang salah dengan mekanisme kuncinya—seperti ketidakcocokan yang tidak terduga dalam kueri skema database.

Akar masalahnya terletak pada cara kerja Django Rest Framework Otentikasi Token berinteraksi dengan penyewa Django perpustakaan. Secara khusus, token ditanyakan terhadap skema publik alih-alih skema penyewa, menyebabkan a Pelanggaran ForeignKey kesalahan. Mari selami masalah ini, temukan penyebabnya, dan perbaiki pintu masuk untuk semua subdomain Anda! 🔧

Memerintah Contoh Penggunaan
schema_context() Mengizinkan peralihan antar skema dalam pengaturan Django multi-penyewa. Contoh: dengan skema_konteks('nama_penyewa'): memastikan operasi dijalankan dalam skema database penyewa yang ditentukan.
authenticate() Mengautentikasi pengguna menggunakan kredensial mereka. Contoh: pengguna = autentikasi(permintaan, nama pengguna=nama pengguna, kata sandi=kata sandi) memeriksa apakah kredensial yang diberikan valid.
Token.objects.get_or_create() Mengambil token yang ada untuk pengguna atau membuat token jika tidak ada. Contoh: token, dibuat = Token.objects.get_or_create(pengguna=pengguna).
csrf_exempt Menonaktifkan perlindungan CSRF untuk tampilan tertentu. Contoh: @csrf_exempt digunakan saat menangani permintaan API eksternal atau non-browser.
connection.tenant.schema_name Mengambil nama skema penyewa saat ini di aplikasi multi-penyewa Django. Contoh: nama_penyewa = koneksi.penyewa.nama_skema.
JsonResponse() Mengembalikan data berformat JSON sebagai respons HTTP. Contoh: return JsonResponse({"status": "sukses", "token": token.key}).
APIClient() Klien pengujian Django Rest Framework yang memungkinkan simulasi permintaan HTTP dalam pengujian. Contoh: mandiri.klien = APIClient().
localStorage.setItem() Menyimpan pasangan nilai kunci di penyimpanan lokal browser. Contoh: localStorage.setItem('token', data.token) menyimpan token untuk digunakan di masa mendatang.
Swal.fire() Menampilkan popup peringatan menggunakan perpustakaan SweetAlert2. Contoh: Swal.fire({icon: 'error', title: 'Login Failed'}) menampilkan gaya pesan kesalahan.
TestCase Digunakan untuk menulis pengujian unit di Django. Contoh: class TenantLoginTest(TestCase): membuat kelas pengujian untuk pengujian login khusus skema.

Menguasai Otentikasi Khusus Penyewa di Django-Tenants

Skrip yang disediakan di atas mengatasi masalah kritis dalam aplikasi Django multi-penyewa di mana token ditanyakan dari skema publik alih-alih skema penyewa yang sesuai. Perilaku ini terjadi karena Django Rest Framework (DRF) tidak secara otomatis mengganti skema ketika berinteraksi dengan model token. Untuk mengatasi hal ini, kami memanfaatkan penyewa Django perpustakaan skema_konteks metode, memungkinkan kami mengeksekusi kueri database secara eksplisit dalam skema penyewa yang benar. Hal ini memastikan bahwa autentikasi pengguna dan pengambilan token berfungsi dengan lancar untuk setiap penyewa, baik diakses melalui domain primer atau subdomain. Tanpa penyesuaian ini, kesalahan ForeignKeyViolation terjadi karena sistem mencari catatan pengguna dalam skema yang salah.

Fungsi `dual_login_view` menunjukkan cara mengautentikasi pengguna sekaligus memastikan koneksi database mengarah ke skema penyewa. Pertama, ia mengekstrak nama pengguna dan kata sandi dari payload permintaan. Kemudian, dengan menggunakan metode `otentikasi`, ini memvalidasi kredensial. Jika berhasil, pengguna akan login dan membuat token menggunakan metode `Token.objects.get_or_create()` DRF. Untuk memastikan kueri ini menargetkan skema yang benar, fungsi `schema_context` menggabungkan logika, mengalihkan konteks database ke skema penyewa aktif. Hal ini menjamin sistem dapat menemukan catatan pengguna dan token yang benar, sehingga menghilangkan kesalahan ketidakcocokan skema.

Kelas `TenantAwareLoginAPIView` meningkatkan solusi dengan mengadopsi APIView Django Rest Framework untuk pendekatan modular. Ia menerima permintaan POST yang berisi kredensial pengguna, memvalidasinya menggunakan `otentikasi`, dan menghasilkan token jika kredensialnya benar. Yang penting, ia menggunakan `schema_context` untuk menjalankan semua operasi dalam skema penyewa yang benar. Tampilan berbasis kelas ini ideal untuk implementasi API modern karena memusatkan penanganan kesalahan dan memberikan respons yang bersih dan terstruktur. Misalnya, mengembalikan token JSON memastikan bahwa frontend dapat menyimpannya di penyimpanan lokal dan menggunakannya untuk permintaan terotentikasi berikutnya.

Di frontend, skrip pengiriman formulir JavaScript memainkan peran penting dalam membuat permintaan yang aman dan terstruktur ke titik akhir login. Ini mencegah perilaku formulir default, memvalidasi kolom input, dan mengirimkan kredensial bersama dengan token CSRF melalui permintaan API pengambilan. Setelah menerima respons yang berhasil, token disimpan di `Penyimpanan lokal` dan pengguna dialihkan. Jika server mengembalikan kesalahan, perpustakaan SweetAlert2 menampilkan pesan peringatan ramah. Hal ini membuat pengalaman pengguna lebih lancar dan memastikan umpan balik kesalahan yang tepat. Misalnya, saat mengakses subdomain penyewa, pengguna yang masuk dengan kredensial yang valid akan segera melihat pesan sukses dan diarahkan ke dasbor aplikasi. 🔒

Menangani Masalah Masuk Subdomain di Django-Tenants dengan Kueri Skema yang Dioptimalkan

Solusi backend menggunakan Django ORM dengan pemilihan skema eksplisit dan penanganan kesalahan.

# 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)

Manajemen Token Eksplisit Menggunakan Skema Sadar Penyewa

Tampilan API Django yang termodulasi dan dapat digunakan kembali untuk masuk dalam arsitektur multi-penyewa.

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)

Skrip Frontend untuk Menangani Permintaan Login Subdomain

Solusi JavaScript untuk menangani pengiriman formulir dan proses login berbasis token untuk subdomain penyewa.

<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>

Tes Unit untuk Memverifikasi Otentikasi Token Sadar Skema

Uji unit dengan Python untuk memastikan API menangani peralihan skema dengan benar.

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())

Memahami Peran Kueri Token Spesifik Penyewa dalam Aplikasi Django Multi-Penyewa

Salah satu aspek utama dari aplikasi Django multi-penyewa memastikan bahwa operasi database selalu terjadi dalam skema penyewa yang benar. Masalah dalam kasus ini terjadi karena perilaku default Django mengasumsikan skema bersama tunggal, menyebabkan kesalahan ketika token atau pengguna tidak dapat ditemukan di skema publik. Dengan memanfaatkan alat seperti schema_context fungsi dari penyewa Django perpustakaan, kami secara eksplisit beralih antar skema untuk melakukan kueri spesifik penyewa. Hal ini memastikan bahwa kueri autentikasi untuk pengguna dan token diarahkan ke skema yang benar.

Detail penting lainnya yang sering diabaikan adalah caranya Token.objects.get_or_create() beroperasi. Secara default, ini mencari catatan pengguna dalam skema database aktif. Jika skema saat ini salah, kueri gagal dengan a Pelanggaran ForeignKey kesalahan. Untuk memperbaikinya, kami memastikan bahwa setiap kueri yang melibatkan model token terjadi dalam konteks skema penyewa yang tepat. Tanpa penyesuaian ini, bahkan pengguna yang valid pun akan gagal melakukan autentikasi karena ID pengguna tidak dapat ditemukan di skema default.

Selain itu, kode front-end memainkan peran penting dalam berkomunikasi secara efektif dengan proses backend ini. Memastikan API pengambilan mengirimkan tanda CSRF dan menangani respons JSON dengan benar sangatlah penting. Misalnya, menggabungkan panggilan API dalam blok coba-tangkap dan menangani kesalahan menggunakan pustaka yang mudah digunakan seperti SweetAlert2 meningkatkan kegunaan. Penyempurnaan ini memastikan alur login tetap lancar, bahkan saat beralih antar subdomain atau mengalami kesalahan spesifik skema. Misalnya, bayangkan platform SaaS di mana setiap perusahaan (penyewa) menggunakan subdomain—memperbaiki konteks skema memastikan setiap karyawan login dengan lancar tanpa gangguan. 🚀

Pertanyaan Umum tentang Masalah Masuk Django Multi-Penyewa

  1. Apa yang menyebabkan a 500 Kesalahan Server Internal saat masuk?
  2. Kesalahan terjadi karena Token.objects.get_or_create() menanyakan skema yang salah, menyebabkan ketidakcocokan saat mencari catatan pengguna.
  3. Bagaimana cara memastikan kueri token mengarah ke skema penyewa yang benar?
  4. Menggunakan schema_context() dari penyewa Django perpustakaan untuk menyelesaikan eksekusi kueri dan beralih ke skema yang benar.
  5. Mengapa login panel admin berfungsi tetapi login pengguna gagal?
  6. Admin Django secara otomatis menyesuaikan konteks skema, tetapi tampilan khusus menggunakan authenticate() atau Token.objects mungkin tidak kecuali dikonfigurasi secara eksplisit.
  7. Bagaimana cara mengambil dan menyimpan token login di frontend?
  8. Gunakan API pengambilan untuk mengirim kredensial, lalu simpan token respons menggunakan localStorage.setItem() untuk otentikasi persisten.
  9. Bagaimana cara menampilkan pesan kesalahan yang lebih baik untuk login yang gagal?
  10. Terapkan peringatan frontend menggunakan perpustakaan seperti SweetAlert2 untuk memberi tahu pengguna tentang kredensial yang salah atau masalah server.

Memastikan Proses Masuk yang Lancar di Seluruh Subdomain Penyewa

Menyelesaikan kegagalan masuk dalam aplikasi multi-penyewa Django memerlukan memastikan bahwa semua permintaan basis data beroperasi dalam skema yang tepat. Dengan menggunakan alat seperti konteks skema secara eksplisit, kami dapat menjamin bahwa token pengguna diambil dari database penyewa yang benar, sehingga menghindari konflik skema.

Bayangkan bekerja pada platform SaaS di mana pengguna menghadapi kegagalan login hanya pada subdomain. Dengan peralihan skema yang tepat, masalah ini teratasi, sehingga memastikan autentikasi yang lancar. Mengadopsi perbaikan ini tidak hanya meningkatkan pengalaman pengguna namun juga menjamin akses data yang aman dan efisien untuk setiap penyewa. 🔧

Sumber dan Referensi untuk Memahami Masalah Subdomain Django-Tenant
  1. Dokumentasi terperinci tentang penyewa Django perpustakaan, menjelaskan manajemen skema dalam aplikasi multi-penyewa. Tersedia di: Dokumentasi Django-Penyewa .
  2. Dokumentasi resmi Django Rest Framework (DRF) pada otentikasi token. Pelajari lebih lanjut di: Otentikasi Token DRF .
  3. Panduan komprehensif tentang penggunaan skema_konteks di lingkungan multi-penyewa. Ditemukan di: GitHub - Penyewa Django .
  4. Wawasan mengenai penanganan token CSRF dalam aplikasi Django: Dokumentasi CSRF Django .
  5. Praktik terbaik untuk merancang platform SaaS multi-penyewa, termasuk autentikasi pengguna: Panduan Multi-Sewa SaaS Pegasus .