Запрос OPTIONS получает ответ «401 Unauthorized» - PullRequest
0 голосов
/ 10 января 2020

Я создал API с Symfony 4, который использует пользовательскую проверку токена. Я протестировал API на Postman, и все работает отлично, теперь я хочу использовать API с использованием jQuery и получить все данные, но в браузере я сталкиваюсь с проблемами CORS, как показано ниже:

Доступ к XMLHttpRequest по адресу http://localhost: 8000 / api / reports 'от источника' http://localhost: 8080 'заблокирован политикой CORS: Ответ на запрос предполетной проверки не' t пройти проверку контроля доступа: у него нет статуса HTTP ok.

Вот мой серверный API:

Я реализовал CORSEventSubscriber, чтобы разрешить CORS, например ниже:

class CORSSubscriber implements EventSubscriberInterface
{

/**
 * @var TokenStorageInterface
 */
private $tokenStorage;

public function __construct(TokenStorageInterface $tokenStorage)
{
    $this->tokenStorage = $tokenStorage;
}
public function onKernelResponse(FilterResponseEvent $event)
{
    $responseHeaders = $event->getResponse()->headers;
    $responseHeaders->set('Access-Control-Allow-Origin', '*');
    $responseHeaders->set('Access-Control-Allow-Headers', 'x-auth-token, content-type');
    $responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET');
}

/**
 * @inheritDoc
 */
public static function getSubscribedEvents()
{
    return [
        KernelEvents::RESPONSE => 'onKernelResponse',
    ];
}

Это действие, которое я вызываю в контроллере:

/**
 * @Route("/api/reports",name="reports",methods={"GET","OPTIONS"})
 * @param Request $request
 * @return Response
 * @throws  Exception
 */
function getReports(Request $request){

return new JsonResponse('test', Response::HTTP_UNAUTHORIZED);

}

Я пытался использовать API, как это

    <script>
    $(document).ready(function(){

        authenticate().then(function (data) {
           // the promise resolve the token and data.token output the correct value
           $.ajax({
               url:'http://localhost:8000/api/reports',
               type: 'GET',
                headers: {'X-Auth-Token' : data.token },
               success: function (data) {
                   //append data to your app
                   console.log(data);
               }
           })
        })
    });
    function authenticate() {
        let data={
            "username": "test",
            "password": "test"
        };
        return new Promise(function(resolve, reject) {
            $.ajax({
                url:'http://localhost:8000/api/auth/check',
                type:'POST',
                data:JSON.stringify(data),
                dataType:'Json',
                success: function (data) {
                    console.log(data);
                resolve(data);
                },
                error:function () {
                }
            })
        });
    }


</script>

Я добавил это, чтобы отладить проблему, и обнаружил, что эта функция выполняется только для POST, когда есть метод токена, такой как OPTIONS, он не выполняется

public function onKernelRequest(GetResponseEvent $event)
{
    $this->logger->info($event->getRequest()->getRealMethod());
}

Ответы [ 2 ]

3 голосов
/ 10 января 2020

Вы делаете запрос кросс-источника и добавляете нестандартный заголовок. Это означает, что это Предварительно выданный запрос .

Браузер отправляет запрос OPTIONS, чтобы запросить разрешение на выполнение запроса с пользовательскими заголовками.

Вы не можете контролировать формат запроса предварительной проверки. Вы определенно не можете добавить учетные данные к нему. (Добавление учетных данных - это еще одна вещь, которая превращает простой запрос в предварительно выданный запрос).

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

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


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

Запрос OPTIONS должен относиться только к CORS (и не извлекать какие-либо данные, требующие авторизации).

Запрос GET должен требовать авторизации и возврата данных.

1 голос
/ 13 января 2020

Через несколько дней я исправил это, добавив к CorsSubscriber

public function onKernelResponse(FilterResponseEvent $event)
{

    $responseHeaders = $event->getResponse()->headers;
    $responseHeaders->set('Access-Control-Allow-Origin', 'http://localhost:8080');
    $responseHeaders->set('Access-Control-Allow-Credentials', 'true');
    $responseHeaders->set('Access-Control-Allow-Headers', ' content-type ,x-auth-token');
    $responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET');
    if($event->getRequest()->getRealMethod()=='OPTIONS'){
        $responseHeaders->set('Access-Control-Max-Age', '1728000');
        $event->getResponse()->setStatusCode(200);
    }

}

после обработки ответа, который я посылаю 200 в качестве кода состояния, поэтому у меня не будет никаких проблем CORS

...