Я работаю над интерфейсом реагирования, используя 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) работает по назначению. А вот с удалением курьера до обновления удаляет мой аппарат.
Я надеюсь, что кто-нибудь может помочь мне с этим.
@Jan Garaj Насколько я понимаю, Keycloak предназначен только для аутентификации. DELETE запускается для REST API бэкэнда Java с использованием Keycloak для аутентификации пользователя/браузера в бэкэнде. Я мог бы представить, что Keycloak не разрешает браузеру отправлять запрос DELETE, но это всего лишь предположение, основанное на различных статьях, которые я читал, сообщении «выборки» из браузера и том, что REST API не вызывается из браузера. Я не знаю, как это проверить или даже настроить метод DELETE в Keycloak.
Вы смешиваете несколько ошибок здесь. Сначала отключите любую аутентификацию/keycloak и устраните проблемы CORS в интерфейсе кода<->внутреннем интерфейсе. Access to XMLHttpRequest at 'http://192.168.0.66:8080/mystique/rest/websocket-auth/token' from origin 'http://localhost:3000' это определенно не проблема с Keycloak.
@JanGaraj Хорошо. Я попробую это. Но это займет некоторое время. Кажется, что деактивировать Keycloak не так просто. Я скажу вам, когда у меня будут новости. Спасибо.
@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: Удаление устройств произошло по моей вине, перепутал несколько переменных.




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