React (CORS с Keycloak): заголовок не установлен или заголовок установлен дважды, нет вызова OPTIONS, но статус HTTP (отменен)

Я работаю над интерфейсом реагирования, используя REST для связи с бэкэндом JAVA (микросервис Thorntail), защищенным Keycloak. При использовании GET и POST проблем нет, но попытка DELETE возвращает разные ошибки в зависимости от моих настроек. Мой файл CorsFilter.java по умолчанию не имеет настроек:

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;

@Provider
public class CorsFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext,
                       ContainerResponseContext responseContext) { 
    }
}

Моя функция React REST:

static deleteCourier = function (origin, courierNumber, endpoint, data, requestListener) {
    keycloak.updateToken(5).then(function () {
        const request = new XMLHttpRequest();
        request.open("DELETE", HTTP_SCHEME + "://" + backendUrl + endpoint + "/" + origin + "/" + courierNumber);
        request.setRequestHeader('Authorization', 'Bearer' + keycloak.token);
        request.send();
    }).catch(function () {
        console.info('Failed to refresh the token, or the session has expired');
        keycloak.init({onLoad: 'login-required'}).success(function (authenticated) {
            if (authenticated) {
                Rest.deleteCourier(origin, courierNumber, endpoint, data, requestListener);
            } else {
                console.info('kc not authenticated');
            }
        }).error(function () {
            console.info('kc init failed');
        });
    }).then(function () {
        Rest.updateData(data, requestListener, endpoint)
    });
};

Вызов REST API бэкенда:

import javax.ejb.EJB;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/device")
public class DeviceEndpoint {   

    @DELETE
    @Path("/{origin}/{courierNumber}")
    public Response delete(
            @PathParam("origin") String origin,
            @PathParam("courierNumber") String courierNumber) {
        try {
            deviceBF.removeCourier(origin, courierNumber);
        } catch (PhoenixClientException e) {
            return Response.ok(new WebApplicationException(e)).build();
        }
        return Response.ok().build();
    }
}

В Keycloak для «Web Origins» установлено значение «*».

При использовании этой настройки GET и POST работают по назначению. При попытке удалить устройство вкладка сети в моем браузере показывает мне статус: «(отменено)» и (скопировано как выборка из Google Chrome):

fetch("http://192.168.0.66:8282/auth/realms/customer/protocol/openid-connect/auth?response_type=code&client_id=mystique&redirect_uri=http%3A%2F%2F192.168.0.66%3A8080%2Fmystique%2Frest%2Fdevice%2Fdts%2Fd&state=22a1dba6-e12e-4852-8cba-0f86a4799d4f&login=true&scope=openid", {"credentials":"omit","referrer":"http://localhost:3000/","referrerPolicy":"no-referrer-when-downgrade","body":null,"method":"DELETE","mode":"cors"});

И вывод консоли:

Access to XMLHttpRequest at 'http://192.168.0.66:8080/mystique/rest/device/dts/d' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Запросы GET и POST отправляют запрос OPTIONS перед реальным запросом. В этом случае такой запрос OPTIONS не отправляется.

Когда я помещаю вывод консоли в свой REST API, я вижу, что он не вызывается. Но путь должен быть в порядке. Протестировал REST API через Postman и все заработало.

Если я изменю файл CorsFilter.java и добавлю, например:

    responseContext.getHeaders().add(
            "Access-Control-Allow-Origin", "http://localhost:3000");

... консоль браузера показывает мне:

Access to XMLHttpRequest at 'http://192.168.0.66:8080/mystique/rest/websocket-auth/token' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:3000, http://localhost:3000', but only one is allowed.

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

Добавление следующего в CorsFilter.java, похоже, не имеет никакого эффекта.

responseContext.getHeaders().add(
            "Access-Control-Allow-Methods",
            "GET, POST, PUT, DELETE, OPTIONS");

В дополнение к ранее описанному поведению устройство, которому принадлежит курьер, удаляется. Я не уверен, соответствует ли это проблеме с CORS или это единственная проблема. Изменение данных устройства без удаления курьера (что также делается через REST) ​​работает по назначению. А вот с удалением курьера до обновления удаляет мой аппарат.

Я надеюсь, что кто-нибудь может помочь мне с этим.

Просто для подтверждения: ваш код запускает запрос DELETE к вашему Keycloak? Также похоже, что ваше приложение (192.168.0.66:8080) не предоставляет правильный ответ CORS для интерфейса (локальный: 3000)

Jan Garaj 05.03.2019 22:46

@Jan Garaj Насколько я понимаю, Keycloak предназначен только для аутентификации. DELETE запускается для REST API бэкэнда Java с использованием Keycloak для аутентификации пользователя/браузера в бэкэнде. Я мог бы представить, что Keycloak не разрешает браузеру отправлять запрос DELETE, но это всего лишь предположение, основанное на различных статьях, которые я читал, сообщении «выборки» из браузера и том, что REST API не вызывается из браузера. Я не знаю, как это проверить или даже настроить метод DELETE в Keycloak.

Carsten 05.03.2019 23:31

Вы смешиваете несколько ошибок здесь. Сначала отключите любую аутентификацию/keycloak и устраните проблемы CORS в интерфейсе кода<->внутреннем интерфейсе. Access to XMLHttpRequest at 'http://192.168.0.66:8080/mystique/rest/websocket-auth/token‌​' from origin 'http://localhost:3000' это определенно не проблема с Keycloak.

Jan Garaj 05.03.2019 23:51

@JanGaraj Хорошо. Я попробую это. Но это займет некоторое время. Кажется, что деактивировать Keycloak не так просто. Я скажу вам, когда у меня будут новости. Спасибо.

Carsten 06.03.2019 21:31

@JanGaraj Кажется, мне удалось деактивировать Keycloak. После этого мне также пришлось добавить заголовки в CorsFilter.java ("Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, HEAD" , "Access-Control-Allow-Headers": "content-type"). Это было все, чтобы обеспечить правильное поведение REST API. Для меня это выглядит так, как будто все проблемы исходили от Keycloak!?!? PS: Удаление устройств произошло по моей вине, перепутал несколько переменных.

Carsten 11.03.2019 16:41
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
5
1 174
0

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