Python Flask CORS - API всегда разрешает любое происхождение
Я просмотрел много SO-ответов и не могу найти эту проблему. У меня такое чувство, что я просто упускаю что-то очевидное.
У меня есть базовый API Flask, и я реализовал и расширение flask_cors, и собственный декоратор Flask [@crossdomain от Armin Ronacher]. 1 ( http://flask.pocoo.org/snippets/56/) Обе показывают одну и ту же проблему.
Это мой пример приложения:
application = Flask(__name__,
static_url_path='',
static_folder='static')
CORS(application)
application.config['CORS_HEADERS'] = 'Content-Type'
@application.route('/api/v1.0/example')
@cross_origin(origins=['http://example.com'])
# @crossdomain(origin='http://example.com')
def api_example():
print(request.headers)
response = jsonify({'key': 'value'})
print(response.headers)
return response
(EDIT 3 вставлено):
Когда я делаю GET-запрос к этой конечной точке от JS в браузере (от 127.0.0.1), он всегда возвращает 200, когда я ожидал увидеть:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:5000' is therefore not allowed access. The response had HTTP status code 403.
CURL:
ACCT:ENVIRON user$ curl -i http://127.0.0.1:5000/api/v1.0/example
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 20
Access-Control-Allow-Origin: http://example.com
Server: Werkzeug/0.11.4 Python/2.7.11
Date: [datetime]
{
"key": "value"
}
ЖУРНАЛ:
Content-Length:
User-Agent: curl/7.54.0
Host: 127.0.0.1:5000
Accept: */*
Content-Type:
Content-Type: application/json
Content-Length: 20
127.0.0.1 - - [datetime] "GET /api/v1.0/example HTTP/1.1" 200 -
Я даже не вижу всех правильных заголовков в ответе, и, кажется, не волнует, что источник в запросе.
Есть идеи, что мне не хватает? Спасибо!
РЕДАКТИРОВАТЬ:
В качестве примечания, посмотрев пример документации здесь ( https://flask-cors.readthedocs.io/en/v1.7.4/), он показывает:
@app.route("/")
def helloWorld():
'''
Since the path '/' does not match the regular expression r'/api/*',
this route does not have CORS headers set.
'''
return '''This view is not exposed over CORS.'''
... что довольно интересно, так как у меня уже есть корневой путь (и другие), выставленные без какого-либо украшения CORS, и они отлично работают из любого источника. Таким образом, кажется, что с этой настройкой что-то принципиально не так.
В соответствии с этим, учебник здесь ( https://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask), по-видимому, указывает, что Apis Flask, естественно, должен быть выставлен без защиты (я Я бы предположил, что это только потому, что расширение CORS не было применено), но мое приложение в основном просто работает, как расширение CORS даже не существует (кроме нескольких заметок в журнале, которые вы можете увидеть).
РЕДАКТИРОВАТЬ 2:
Мои комментарии были неясными, поэтому я создал три примера конечных точек на AWS API Gateway с различными настройками CORS. Это конечные точки метода GET, которые просто возвращают "успех":
1) CORS не включен (по умолчанию):
Отклик:
XMLHttpRequest не может загрузить https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-default. Ответ на запрос предварительной проверки не проходит проверку контроля доступа: в запрошенном ресурсе отсутствует заголовок "Access-Control-Allow-Origin". Поэтому источнику " http://127.0.0.1:5000/" запрещен доступ. Ответ имел HTTP-код состояния 403.
2) CORS включен - источник ограничен:
Access-Control-Allow-Headers: 'Content-Type'
Access-Control-Allow-Origin: ' http://example.com/'
- Конечная точка: https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-enabled-example
Отклик:
XMLHttpRequest не может загрузить https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-enabled-example. Ответ на запрос предварительной проверки не проходит проверку контроля доступа: заголовок "Access-Control-Allow-Origin" имеет значение " http://example.com/", которое не равно указанному источнику. Поэтому источнику " http://127.0.0.1:5000/" запрещен доступ.
3) CORS включен - подстановочный знак происхождения:
- Access-Control-Allow-Headers: 'Content-Type'
- Access-Control-Allow-Origin: '*'
- Конечная точка: https://t9is0yupn4.execute-api.us-east-1.amazonaws.com/prod/cors-enabled-wildcard
Отклик:
"success"
Я не очень разбираюсь в инфраструктуре, но я ожидал, что включение расширения Flask CORS заставит мои конечные точки API имитировать это поведение в зависимости от того, что я установил на origins=
установка. Чего мне не хватает в этой настройке Flask?
РЕШЕНИЕ РЕДАКТИРОВАТЬ:
Хорошо, учитывая, что что-то с моей стороны было явно ненормальным, я сократил свое приложение и повторно реализовал некоторые очень базовые API для каждого варианта ограничения происхождения CORS. Я использовал эластичный beanstalk AWS для размещения тестовой среды, поэтому я перегрузил эти примеры и выполнил запрос JS ajax для каждого из них. Это сейчас работает.
Я получаю Access-Control-Allow-Origin
ошибка на голых конечных точках. Похоже, что когда я настроил приложение для развертывания, я раскомментировал CORS(application, resources=r'/api/*')
что явно позволяло все происхождение для голых конечных точек!
Я не уверен, почему мой маршрут с определенным ограничением (origins=[]
) также разрешал все, но это, должно быть, была опечатка или что-то маленькое, потому что это работает сейчас.
Отдельное спасибо sideshowbarker за помощь!
1 ответ
Из вашего вопроса как есть, не совсем понятно, какое поведение вы ожидаете. Но что касается работы протокола CORS, кажется, что ваш сервер уже ведет себя как ожидалось.
В частности, curl
Ответ, приведенный в вопросе, показывает этот заголовок ответа:
Access-Control-Allow-Origin: http://example.com
Это означает, что сервер, уже настроенный для оповещения браузеров, разрешает только запросы кросс-источника из внешнего кода JavaScript, выполняющегося в браузерах, если код выполняется в источнике http://example.com
,
Если ожидаемое поведение таково, что сервер теперь будет отклонять запросы от не-браузерных клиентов, таких как curl
тогда конфигурация CORS сама по себе не заставит сервер это делать.
Единственное, что сервер делает по-другому, когда вы настраиваете его с поддержкой CORS, это просто отправка Access-Control-Allow-Origin
заголовок ответа и другие заголовки ответа CORS. Вот и все.
Фактическое применение ограничений CORS осуществляется только браузерами, а не серверами.
Таким образом, независимо от того, какую конфигурацию CORS на стороне сервера вы выполняете, сервер все равно продолжает принимать запросы от всех клиентов и отправляет их иначе; другими словами, все клиенты из всех источников продолжают получать ответы от сервера так же, как и в противном случае.
Но браузеры будут отображать ответы от запросов из разных источников только для внешнего кода JavsScript, выполняющегося в определенном источнике, если сервер, на который был отправлен запрос, разрешает разрешение на запрос, отвечая Access-Control-Allow-Origin
заголовок, который позволяет это происхождение.
Это единственное, что вы можете сделать, используя конфигурацию CORS. Вы не можете заставить сервер только принимать и отвечать на запросы от определенных источников, просто выполняя любую конфигурацию CORS на стороне сервера. Для этого вам нужно использовать что-то отличное от конфигурации CORS.