Django-rest-framework: DRF должен разрешать все запросы OPTIONS по умолчанию

Созданный на 21 нояб. 2017  ·  22Комментарии  ·  Источник: encode/django-rest-framework

По итогам обсуждения # 908

Разрешения для запросов OPTIONS (метаданные) неправильно обрабатываются в DRF.

Согласно спецификациям W3C , все предварительные запросы OPTIONS НЕ аутентифицируются, то есть пользователи всегда будут получать ошибку 401 при предварительной проверке запроса на аутентифицированные конечные точки, потому что современные браузеры никогда не отправляют это в соответствии со спецификациями:

В противном случае сделайте предварительный запрос. Получите URL-адрес запроса из источника источника, используя источник реферера в качестве источника переопределения источника реферера с флагом ручного перенаправления и установленным флагом файлов cookie блокировки, используя метод OPTIONS и со следующими дополнительными ограничениями:

  • Включите заголовок Access-Control-Request-Method со значением поля заголовка для метода запроса (даже если это простой метод).
  • Если заголовки запроса автора не пустые, включите заголовок Access-Control-Request-Headers с в качестве значения поля заголовка список разделенных запятыми имен полей заголовков из заголовков запроса автора в лексикографическом порядке, каждый из которых преобразован в нижний регистр ASCII (даже если один или еще простой заголовок).
  • Исключить заголовки запроса автора.
  • ➡️ Исключить учетные данные пользователя .
  • Исключить тело объекта запроса.

Я думаю, что это должно быть поведение по умолчанию.
DRF должен авторизовать все запросы OPTIONS по умолчанию для стандартных классов разрешений (IsAuthenticated, IsAdminUser и т. Д.), И пользователи могут переопределить это, когда им явно необходимо защитить информацию о метаданных (нарушая стандартную совместимость CORS)

Действия по воспроизведению :

views.py

class MyView(APIView):

    permission_classes = (IsAuthenticated,)

urls.py

urlpatterns = [
    url(r'^myview/', MyView.as_view()),
]

консоль

http GET http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

http OPTIONS http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

Ожидаемое поведение

http GET http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

http OPTIONS http://127.0.0.1:8000/myview/
HTTP/1.0 200 OK

Временная работа

class IsAuthenticated(permissions.IsAuthenticated):

    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return super(IsAuthenticated, self).has_permission(request, view)

Самый полезный комментарий

Версия DRF: 3.7.3
Python 3.6.3

Временное решение, упомянутое выше, у меня не сработало. Все запросы аутентифицировались независимо от того, были ли они PUT, POST, GET, OPTIONS и т. Д.

Он работал над изменением его на:

# myapp/permissions.py
from rest_framework.permissions import IsAuthenticated

class AllowOptionsAuthentication(IsAuthenticated):
    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return request.user and request.user.is_authenticated

И в settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication',),
    'DEFAULT_PERMISSION_CLASSES': (
        'myapp.permissions.AllowOptionsAuthentication',
    )
}

Все 22 Комментарий

Версия DRF: 3.7.3
Python 3.6.3

Временное решение, упомянутое выше, у меня не сработало. Все запросы аутентифицировались независимо от того, были ли они PUT, POST, GET, OPTIONS и т. Д.

Он работал над изменением его на:

# myapp/permissions.py
from rest_framework.permissions import IsAuthenticated

class AllowOptionsAuthentication(IsAuthenticated):
    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return request.user and request.user.is_authenticated

И в settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication',),
    'DEFAULT_PERMISSION_CLASSES': (
        'myapp.permissions.AllowOptionsAuthentication',
    )
}

Я тоже столкнулся с той же проблемой. Я согласен с предложенным решением и благодарю за временное решение!

Не на 100% убеждены в том, что «должен разрешать все запросы OPTIONS по умолчанию» - это именно то поведение, которое мы хотим, поскольку существует множество разработчиков, использующих среду REST, которые используют запросы OPTIONS для случаев, отличных от предварительных запросов CORS.

Однако я думаю, что мы, вероятно, действительно хотим иметь благословенный вариант CORS. Я не знаю, означает ли это, что мы должны включать https://github.com/ottoyiu/django-cors-headers/ напрямую, или нам следует ссылаться на него более подробно.

Решается ли эта проблема после использования этого пакета?

Этот пакет на самом деле не является решением, он просто добавляет заголовки CORS, но не исправляет тот факт, что OPTIONS возвращает HTTP401, если разрешение DRF специально не предоставлено для всех неаутентифицированных запросов.

ИМО это должно быть введено наоборот, то есть разрешено по умолчанию с уведомлением о критических изменениях.
Это ожидаемое поведение в соответствии со спецификациями W3C, и упоминание третьей стороны в документе для исправления неправильной реализации на самом деле не является чистым решением ...

Поэтому, хотя есть люди, использующие OPTIONS для вещей, не связанных с CORS (я один из них), потенциально гораздо больше неявно ожидают, что что-то будет работать из коробки, поскольку механизмы CORS применяются все большим и большим количеством браузеров. Фактически, эти механизмы потенциально генерируют 99% + запросов OPTIONS через Интернет.

Интересный конфликт. Я полностью понимаю проблему с неявным разрешением по умолчанию для метода OPTIONS. Я, естественно, более склонен к более безопасному решению и полагаю, что это зависит от цели разработчика для DRF. Так что отказ по умолчанию кажется мне более подходящим.

Также возможно, что спецификация W3C для разрешения OPTIONS применяется только в контексте CORS. Очевидно, что DRF не может узнать контекст и должен быть настройкой, предоставляемой разработчику.

Если предназначен CORS, разрешите все запросы OPTIONS. CORS по умолчанию является непреднамеренным.

На самом деле я думаю, что мы могли бы рассмотреть критическое изменение для основной версии, оставив текущее поведение доступным. Наше существующее поведение OPTIONS было на месте, так как JSONP был тем, что люди использовали бы, а не CORS, поэтому нам, вероятно, необходимо обновление, которое удаляет довольно специальный набор информации по умолчанию, который мы предоставляем, и вместо этого концентрируется исключительно на OPTIONS для CORS по умолчанию .

+1

@tomchristie вы знаете, когда произойдет обновление / исправление основной версии? Я тоже сталкиваюсь с этой проблемой.

Между тем обходной путь

Сделайте это, чтобы убедиться, что он получил должное внимание для версии 3.9

Альтернативный обходной путь - обработать это явно в представлении. В случае, когда у вас есть несколько классов разрешений, это более СУХОЙ, поскольку каждому из них потребуется такая обработка.

def check_permissions(self, request):
        if request.method == 'OPTIONS':
            return
        super(MyApiView, self).check_permissions(request)

Возвращаясь к этому, рассмотрев это дальше, - пакет https://github.com/OttoYiu/django-cors-headers обрабатывает предварительно заданные OPTIONS запросы в промежуточном программном обеспечении и возвращает ответ напрямую. Неважно, что здесь делает REST-фреймворк, потому что запрос / ответ перехватывается до того, как он вообще попадает в REST-фреймворк.

Для меня не очевидно, что у нас здесь проблема.

Ответы перед проверкой не касаются структуры REST: https://github.com/ottoyiu/django-cors-headers/blob/master/corsheaders/middleware.py#L83

Спасибо. Мы не используем django-cors-headers, но, возможно, нам стоит их использовать.
Я все еще согласен с предыдущими комментариями о том, что DRF не должен нуждаться во внешнем пакете для обработки запросов CORS, совместимых с W3C.

Да, есть множество способов / сторонних пакетов, чтобы обойти проблему.
Но опять же, этот билет был создан, потому что DRF несовместим со спецификациями W3C CORS, и его следует исправить.

В настоящее время подавляющее большинство запросов OPTIONS выполняемых к конечным точкам, предназначено для предварительной проверки, и, вероятно, новые пользователи DRF вводят в заблуждение необходимость решать эти проблемы вручную из-за упрямого выбора DRF.

В настоящее время подавляющее большинство запросов OPTIONS выполняемых к конечным точкам, предназначено для предварительной проверки, и, вероятно, новые пользователи DRF вводят в заблуждение необходимость решать эти проблемы вручную из-за упрямого выбора DRF.

Тот факт, что CORS перехватил метод OPTIONS, не означает, что его безопасность должна быть изменена по умолчанию для соответствия. Особенно, если поддержка CORS реализована должным образом, она будет работать так, как нужно. Извините, но я думаю, что разработчики, которые хотят, чтобы это было изменено, должны проверять свое собственное мнение, а не разработчиков DRF.

Возможно, расширение документации предполагает, что, если потребуется CORS, использовать модуль, помогающий в правильной реализации, вместо того, чтобы заново изобретать колесо.

Давайте снизим уровень.

Промежуточное ПО - это разумное место для работы с заголовками CORS. Мы могли бы встроить это в структуру REST, но в существующем пакете это уже хорошо предусмотрено.

Тело, которое REST framework возвращает для запросов OPTIONS здесь не имеет значения, так как предварительно настроенные запросы CORS в любом случае должны перехватываться промежуточным программным обеспечением, а стандартные запросы CORS могут относиться к любому методу HTTP.

Я был бы совершенно счастлив, если бы REST-фреймворк перешел к тому, чтобы не обслуживать эти тела ответов по умолчанию, но это немного отличается от проблемы поддержки CORS, и дело не столько в том, что REST-фреймворк ведет себя упрямо, а в том, что он имеет поведение, предшествовавшее широкому внедрению CORS.

Мне кажется, что одного промежуточного программного обеспечения недостаточно или, по крайней мере, требуется некоторое сотрудничество со стороны DRF. Если вы посмотрите на указанный код, вы увидите, что глобальные значения по умолчанию используются для предоставления заголовков CORS. Но как мне узнать глобально, какие заголовки поддерживает каждое представление?

Таким образом, я хотел бы увидеть стандартный способ для промежуточного программного обеспечения подключаться к этим параметрам конфигурации из наборов / представлений: например, метод allowed_cors_headers .

Я согласен с тем, что это не должно обрабатываться представлениями, но абсолютно необходимо уважать знание представления о том, что оно может служить.

Также может быть целесообразно применить переопределение на уровне маршрутизатора ко всем представлениям в маршрутизаторе.

Дополнительные соображения:

  • варьируется в зависимости от происхождения
  • варьируется в зависимости от типа содержимого

Это не мой любимый выбор, но тенденция к использованию сторонних производителей.

Я думаю, что мы можем закрыть этот тикет, как только документация будет обновлена ​​надлежащей информацией для пользователей CORS (например: «Остерегайтесь, DRF не выполняет спецификации W3C CORS для запросов OPTIONS. Если вы используете OPTIONS для CORS, не забудьте добавить правильное промежуточное программное обеспечение, иначе ваши предварительные запросы могут не сработать из-за отсутствия авторизации "и т. д.)

Существующая документация https://www.django-rest-framework.org/topics/ajax-csrf-cors/#cors является вполне разумной, и работа с CORS в промежуточном программном обеспечении является правильным подходом в любом случае.

Но как мне узнать глобально, какие заголовки поддерживает каждое представление?

Вам не нужно - вам нужно знать, какова политика CORS сайта.

С радостью принимаю пул-реквест, делающий документы CORS более заметными или включающий их в другое подходящее место. Кроме этого, здесь нет никаких серьезных проблем.

Мое непонимание спецификации, ой.

В этом случае поддержку лучше включить в вклад сайтов django.
пакет, а не drf.

Le mar. 19 февр. 2019 10:22 утра, Том Кристи [email protected] a
écrit:

Существующая документация
https://www.django-rest-framework.org/topics/ajax-csrf-cors/#cors - это
совершенно разумно, и работа с CORS в промежуточном программном обеспечении является правильным
подход в любом случае.

Но как мне узнать глобально, какие заголовки поддерживает каждое представление?

Вам не нужно - вам нужно знать, какова политика CORS сайта.

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/encode/django-rest-framework/issues/5616#issuecomment-465146969 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/AFhtlM6bG-Bs2CvoO972pIfwvxLHbzAxks5vPAjAgaJpZM4Qlvkn
.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги