Невозможно войти в поддомен арендатора django, основной домен и вход администратора работают
У меня есть приложение с несколькими арендаторами, использующее библиотеку django-tenants
. При входе в основной URL с созданным суперпользователем страница входа работает совершенно нормально. При использовании адреса поддомена для входа в систему страница возвращает 500 error
при использовании правильного имени пользователя и пароля, которые существуют, а консоль говорит Uncaught (in promise) SyntaxError: Unexpected token '<', " <!doctype "... is not valid JSON
.
При использовании несуществующего имени пользователя вывод 400 Bad Request
.
Странно, но я могу получить доступ к панели администратора поддомена, войти в систему совершенно нормально, изменить URL для перехода к части приложения - и пользователь теперь вошел в систему. После входа в систему я могу отправлять формы в полном порядке, и данные собираются, только на странице входа в систему на поддомене возникает ошибка отправки.
Я потерян, так как последующие формы данных отправляются и проходят правильно, и нет недействительных токенов (из того, что я вижу)
views.py
def dual_login_view(request):
"""Authenticate users with both Django Authentication System
and Django Rest Framework"""
if request.method == "POST":
username = request.POST.get("login")
password = request.POST.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
# Login user and create session
login(request, user)
# Create or get API token
token, created = Token.objects.get_or_create(user=user)
response_data = {"status": "success", "token": token.key}
return JsonResponse(response_data)
else:
return JsonResponse(
{"status": "error", "message": "Username with the password doesn't exist!"}, status=400
)
return JsonResponse(
{"status": "error", "message": "Invalid request method"}, status=405
)
class CustomLoginView(LoginView):
def form_invalid(self, form):
for error in form.errors.values():
for e in error:
messages.error(self.request, e)
return super().form_invalid(form)
class UserLoginAPIView(APIView):
def post(self, request):
if not (request.user and request.user.is_authenticated):
return Response(
{"error": "User not recognized"}, status=status.HTTP_401_UNAUTHORIZED
)
try:
token, created = Token.objects.get_or_create(user=request.user)
return Response({"token": f"Token {token.key}"}, status=status.HTTP_200_OK)
except Exception as e:
print(e)
return Response(
{"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED
)
class UserLoginAPIView(APIView):
def post(self, request):
"""Handle user login and return an authentication token."""
username = request.data.get("username")
password = request.data.get("password")
try:
user = MSPAuthUser.objects.get(username=username)
# Verify password
if not user.check_password(password):
raise ValueError("Invalid credentials")
token, created = Token.objects.get_or_create(user=user)
return Response({"token": f"Token {token.key}"}, status=status.HTTP_200_OK)
except ObjectDoesNotExist:
return Response(
{"error": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED
)
except ValueError as e:
return Response({"error": str(e)}, status=status.HTTP_401_UNAUTHORIZED)
login.js
<script>
let form = document.querySelector('form');
form.addEventListener('submit', function(event) {
event.preventDefault();
var formData = new FormData(this);
form.classList.add('was-validated')
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
return;
}
fetch("{% url 'dual_login' %}", {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': formData.get('csrfmiddlewaretoken'),
}
}).then(response => response.json())
.then(data => {
if (data.status === 'success') {
// Store the token (e.g., in local storage or a cookie)
localStorage.setItem('token', data.token);
// Redirect or update the UI
window.location.href = '/';
} else {
Swal.fire({
icon: 'error',
title: data.message,
showConfirmButton: false,
timer: 1500,
})
}
});
});
</script>
Проверьте на вкладке «Сеть» ответ API. Возможно, вы пытаетесь разобрать что-то, что не является JSON, как JSON.
Ошибка Uncaught (in promise) SyntaxError: Unexpected token '<', " <!doctype "... is not valid JSON
возникает потому, что вызов Token
, как вы заметили, поднимает не пойманное исключение. Что, в свою очередь, означает, что объект token
не содержит токена, а содержит HTML-ответ, отображающий ответ на исключение.
И вы правильно поняли, что решение заключается в исправлении вызова Token
.
Как я могу использовать модель rest_framework.authtoken.models для запроса из правильной схемы базы данных?
К моменту вызова Token
вы уже аутентифицировали пользователя, поэтому следующим шагом будет поиск его ассоциации с арендатором. Затем вы можете использовать менеджер контекста schema_context()
, чтобы направить запрос к нужной схеме.
from django_tenants.utils import schema_context
from .tenants import Tenant # Or whatever your tenant model is
def dual_login_view(request):
"""Authenticate users with both Django Authentication System
and Django Rest Framework"""
if request.method == "POST":
username = request.POST.get("login")
password = request.POST.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
# Login user and create session
login(request, user)
# Retrieve tenant information
tenant = user.tenant # Or whatever is appropriate for you to look up the relationship between the user and the tenant
schema_name = tenant.schema_name
# Create or get API token, schema-aware
with schema_context(schema_name):
token, created = Token.objects.get_or_create(user=user)
response_data = {"status": "success", "token": token.key}
return JsonResponse(response_data)
else:
return JsonResponse(
{"status": "error", "message": "Username with the password doesn't exist!"}, status=400
)
return JsonResponse(
{"status": "error", "message": "Invalid request method"}, status=405
)