У меня есть REST-приложение, которое использует встроенный Jetty в качестве сервера. Большинство конечных точек должны быть общедоступными (и иметь соответствующую встроенную аутентификацию), но некоторые предназначены только для внутреннего использования. Я бы хотел избежать излишней аутентификации на них и вместо этого использовать брандмауэр для ограничения доступа:
Внешне видимые конечные точки обслуживаются через порт 10000, который внешний брандмауэр оставляет открытым.
Внутренне видимые конечные точки обслуживаются через порт 20000, который блокирует внешний брандмауэр.
Однако я не могу понять, как этого добиться с помощью встроенной Jetty. Я попытался создать два объекта Server
, один на порту 10000 с соответствующими зарегистрированными обработчиками сервлетов и один на порту 20000 с соответствующими зарегистрированными обработчиками сервлетов. Однако работает только экземпляр сервера, запущенный вторым; запросы к конечным точкам, размещенным первым запустившимся, приводят к 404 ответам.
В документации Jetty говорится о том, как сделать это с *. Xml-конфигурациями , но не для встроенного экземпляра.
Есть мысли или идеи? Или есть лучший способ добиться внутренней / внешней изоляции конечной точки, который я ищу? Жесткое требование заключается в том, что внутренние и внешние конечные точки должны «работать» в одной и той же JVM.
Редактировать
Оказывается, что проблема была связана с использованием Guice и расширением Guice-servlets (проблемы 618 и 635 ). Запуск двух встроенных экземпляров Jetty работает нормально, как описано в ответе Джеймса Кингсбери ниже.
Guice использует фильтр (GuiceFilter), зарегистрированный в контексте сервера, для получения запросов, требующих внедрения зависимостей в области запросов (DI), и для создания сервлетов и фильтров, требующих DI. К сожалению, он использует статический объект для управления списком сервлетов и связанных с ним фильтров.
В типичной настройке файл guice-servlet.jar, содержащий GuiceFilter
, включен для каждого приложения и, таким образом, загружается различным загрузчиком классов для каждого приложения - и все работает нормально. Не так со встроенным Jetty, где по умолчанию все загружается системным загрузчиком классов по умолчанию.
Решение проблемы Guice
Последний мастер (commit fbbb52dcc92e) Guice содержит обновленный GuiceFilter
с поддержкой динамической ссылки на объект FilterPipeline
(статический объект, вызывающий проблемы). К сожалению, конструктор для внедрения экземпляра FilterPipeline
является закрытым для пакета. Итак, чтобы использовать его, вам нужно создать класс-оболочку в пакете com.google.inject.servlet
, который предоставляет этот конструктор:
package com.google.inject.servlet;
import com.google.inject.Inject;
public class NonStaticGuiceFilter extends GuiceFilter {
/**
* Do not use. Must inject a {@link FilterPipeline} via the constructor.
*/
@SuppressWarnings("unused")
private NonStaticGuiceFilter() {
throw new IllegalStateException();
}
@Inject
public NonStaticGuiceFilter(FilterPipeline filterPipeline) {
super(filterPipeline);
}
}
Чтобы использовать этот класс, создайте экземпляр с помощью инжектора с установленным ServletModule
и зарегистрируйте его на Jetty Context
:
// Create the context handler
ServletContextHandler handler = new ServletContextHandler(myServer, "/context");
// Create the injector, registering your ServletModule
final Injector injector = Guice.createInjector(new MyServletModule());
// Add the Guice listener for this injector
handler.addEventListener(new GuiceServletContextListener() {
@Override
protected Injector getInjector() {
return injector;
}
});
// Filter all requests through Guice via NonStaticGuiceFilter.
// Guice will construct the FilterPipeline instance needed by
// NonStaticGuiceFilter.
handler.addFilter(
new FilterHolder(injector
.getInstance(NonStaticGuiceFilter.class)), "/*", null);