Почему я получаю 403 для POST с DRF и rest_framework_api_key?

Я получаю ответ 403 от сервера в моем новом приложении Django. Это очень просто. У меня даже нет моделей, я просто хочу вернуть аудиофайл, но хочу сделать это через API. Из-за этого, поскольку у меня не будет пользователей, мне нужен ключ API, и я обнаружил, что могу использовать платформу Django REST и ключевые модули API платформы REST. Я следил за краткими инструкциями и, похоже, не получил ответа. Раньше он работал, но аутентифицировался через CSRF, и, как я уже сказал, это будет API, поэтому у меня не будет файлов cookie CSRF.

Вот представление, которое я использую:

@api_view(["POST"])
def tts_view(request):
  data = request.POST

  voice_name = data.get("voice_name")
  text = data.get("text")

  if not voice_name or not text:
    return JsonResponse({"error": "Missing voice_name or text"}, status=400)

  return JsonResponse({"wav": text_to_wav(voice_name, text)}, status=200, safe=False)

Настройки:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_api_key',
    'TTS',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework_api_key.permissions.HasAPIKey",
    ]
}

И выборка (ключ API — это просто тест, так что это не имеет значения):

fetch('/create-speech', {
    method: 'POST',
    body: JSON.stringify({
        voice_name: "es-US-Neural2-B",
        text: "Estoy feliz"
    }),
    headers: { 
        'Authorization': '0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay',
        'Content-Type': 'application/json'
    }
})
.then((resp) => {
    if (!resp.ok) throw Error(`${resp.statusText} - ${resp.status}`);
    return resp.json();
})
.then((wav) => {
    console.info('success');
});

Я делаю выборку в консоли на странице по умолчанию, которая не определена (как я уже сказал, мне нужен только API).

Я пытался включить rest_framework.permissions.AllowAny в DEFAULT_PERMISSION_CLASSES, но это тоже не работает.

Я действительно не знаю, что еще делать, поэтому любая помощь будет оценена по достоинству. Спасибо!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы должны добавить класс разрешения исключения CSRF или декоратор, например:

from django.views.decorators.csrf import csrf_exempt

и над объявлением представления API:

@api_view(["POST"])
@csrf_exempt
def tts_view(request):

При этом убедитесь, что вы передаете свой токен API DRF в заголовках в вызове API как Authorization: Token token_string должно хватить.

Он все еще не работает, но спасибо!

Joaquin 19.04.2023 22:43
Ответ принят как подходящий

Из документации Django REST Framework API Key:

По умолчанию клиенты должны передавать свой ключ API через заголовок авторизации. Он должен быть отформатирован следующим образом:

Authorization: Api-Key <API_KEY>

Вам не хватает части Api-Key (обратите внимание на пробел между ней и частью <API_KEY>). Таким образом, ваш запрос должен быть:

fetch('/create-speech', {
    ...
    headers: {
        'Authorization': 'Api-Key 0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay',
        'Content-Type': 'application/json'
    }
})
...

Ты прав! Мне этого не хватало. Но все равно не работает :(

Joaquin 22.04.2023 21:25

Все еще 403? Какие-нибудь подробности в теле ответа?

Igonato 22.04.2023 22:29

Все еще 403, но я успел рассмотреть детали. Он говорит {\"detail\":\"CSRF Failed: CSRF token missing.\"} при печати функции ответов .text(). Я пытался использовать декоратор csrf_exempt, но он не работает @Igonato

Joaquin 22.04.2023 23:04

Я только что проверил, и я получаю тот же результат, если не включать Api-Key в заголовок Authorization, так что это должно быть какая-то ошибка rest_framework_api_key

Joaquin 22.04.2023 23:35

Это что-то с сетью! Я скачал Postman и все заработало. Теперь мне нужно выяснить, что делать в Интернете

Joaquin 22.04.2023 23:58

Если вы не используете аутентификацию на основе файлов cookie, безопасно полностью отключить защиту csrf. Странно, что декоратор не работал...

Igonato 23.04.2023 00:13

Размещение может иметь значение. Поменяйте его на api_view, посмотрите, поможет ли это.

Igonato 23.04.2023 00:17

Подождите, я получил его на работу! Я удалил файлы cookie, сеанс и csrftoken, и это просто сработало. Я думаю, именно поэтому это сработало на Postman — у него не было csrftoken. Спасибо!

Joaquin 23.04.2023 00:36

Другие вопросы по теме