Могу ли я исключить некоторые конкретные URL извнутри? - PullRequest
119 голосов
/ 26 июня 2010

Я хочу, чтобы какой-то конкретный фильтр применялся ко всем URL-адресам, кроме одного конкретного (т. Е. Для /*, кроме /specialpath).

Есть ли возможность сделать это?


пример кода:

<filter>
    <filter-name>SomeFilter</filter-name>
    <filter-class>org.somproject.AFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SomeFilter</filter-name>
    <url-pattern>/*</url-pattern>   <!-- the question is: how to modify this line?  -->
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Ответы [ 7 ]

145 голосов
/ 26 июня 2010

Стандартный API сервлетов не поддерживает эту возможность. Возможно, вы захотите использовать для этого фильтр перезаписи URL, например Tuckey's (который очень похож на Apache HTTPD mod_rewrite), или добавить проверку в методе doFilter() прослушивания фильтра на /*.

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    // Do your business stuff here for all paths other than /specialpath.
}

Вы можете при необходимости указать игнорируемые пути как init-param фильтра, чтобы вы могли контролировать его в web.xml в любом случае. Вы можете получить его в фильтре следующим образом:

private String pathToBeIgnored;

public void init(FilterConfig config) {
    pathToBeIgnored = config.getInitParameter("pathToBeIgnored");
}

Если фильтр является частью стороннего API и, следовательно, вы не можете его изменить, сопоставьте его с более конкретным url-pattern, например, /otherfilterpath/* и создайте новый фильтр на /*, который перенаправит на путь, соответствующий стороннему фильтру.

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    request.getRequestDispatcher("/otherfilterpath" + path).forward(request, response);
}

Чтобы этот фильтр не вызывал себя в бесконечном цикле, необходимо разрешить ему прослушивать (отправлять) только на REQUEST и сторонний фильтр только на FORWARD.

Смотри также:

13 голосов
/ 23 марта 2012

Я использовал подход , описанный Эриком Даугерти : я создал специальный сервлет, который всегда отвечает кодом 403 и ставил его отображение перед общим.

Фрагмент отображения:

  <servlet>
    <servlet-name>generalServlet</servlet-name>
    <servlet-class>project.servlet.GeneralServlet</servlet-class>
  </servlet>
 <servlet>
    <servlet-name>specialServlet</servlet-name>
    <servlet-class>project.servlet.SpecialServlet</servlet-class>
 </servlet>
 <servlet-mapping>
    <servlet-name>specialServlet</servlet-name>
    <url-pattern>/resources/restricted/*</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
    <servlet-name>generalServlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
 </servlet-mapping>

И класс сервлетов:

public class SpecialServlet extends HttpServlet {
    public SpecialServlet() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
}
7 голосов
/ 20 июня 2013

Этот подход работает, когда вы хотите запретить определенный фильтр и все последующие. Это должно работать хорошо, если вы, например. хотите использовать некоторый контент в качестве статических ресурсов в контейнере сервлета, вместо того, чтобы пропустить логику вашего приложения (через фильтр типа GuiceFilter):

Сопоставьте папку со своими статическими файлами ресурсов с сервлетом по умолчанию. Создайте фильтр сервлетов и поместите его перед GuiceFilter в вашем файле web.xml. В созданном вами фильтре вы можете разделить некоторые запросы на GuiceFilter, а другие - непосредственно диспетчеру. Пример следует ...

web.xml

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>StaticResourceFilter</filter-name>
    <filter-class>com.project.filter.StaticResourceFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>StaticResourceFilter</filter-name>
    <url-pattern>/static/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>guiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>guiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

StaticResourceFilter.class

public class StaticResourceFilter implements Filter {

    private final static Logger LOGGER = LoggerFactory.getLogger(StaticResourceFilter.class);

    private static final String RESOURCE_PATH = "/static/";
    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        LOGGER.info("StaticResourceFilter initialized");
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
                         final FilterChain chain) throws IOException, ServletException {

        String path = ((HttpServletRequest) request).getServletPath();
        if (path.toLowerCase().startsWith(RESOURCE_PATH)) {
            request.getRequestDispatcher(path).forward(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        LOGGER.info("StaticResourceFilter destroyed");
    }
}

К сожалению, если вы просто хотите пропустить один шаг в цепочке фильтров, сохранив следующие, это не сработает.

3 голосов
/ 28 февраля 2017

Мне также пришлось фильтровать по шаблону URL (/ {servicename} / api / stats /) в коде Java.

if (path.startsWith("/{servicename}/api/statistics/")) {
validatingAuthToken(((HttpServletRequest) request).getHeader("auth_token"));
filterChain.doFilter(request, response);            
}

Но странно, что сервлет не поддерживает шаблон URL, кроме (/ *), это должно быть очень распространенным случаем для API сервлетов!

3 голосов
/ 26 июня 2010

Не думаю, что вы можете, единственная альтернатива конфигурации - перечислять пути, которые вы хотите отфильтровать, поэтому вместо /* вы можете добавить некоторые для /this/* и /that/* и т. Д., Но этоне приведет к достаточному решению, если у вас есть много таких путей.

Что вы можете сделать, это добавить параметр в фильтр, обеспечивающий выражение (например, регулярное выражение), которое используется для пропуска функции фильтраза пути совпали.Контейнер сервлетов все равно будет вызывать ваш фильтр для этих URL, но вы будете лучше контролировать конфигурацию.

Редактировать

Теперь, когда вы упомянули, что не можете контролироватьфильтровать, вы можете либо наследовать от этого фильтра, вызывая методы super в его методах, кроме случаев, когда присутствует URL-путь, который вы хотите пропустить, и следовать цепочке фильтров, как предложено @BalusC, либо создать фильтр, который создает ваш фильтрделегаты при тех же обстоятельствах.В обоих случаях параметры фильтра будут включать в себя как параметр выражения, который вы добавляете, так и параметр фильтра, который вы наследуете или делегируете.

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

0 голосов
/ 30 марта 2018

Если по какой-либо причине вы не можете изменить исходное сопоставление фильтра ("/ *" в моем случае) и отправляете на неизменяемый сторонний фильтр, вы можете найти следующее:

  • Перехватить путь, который нужно обойти
  • Пропустить и выполнить последнее кольцо цепочки фильтров (сам сервлет)
  • Пропуск выполняется с помощью отражения, проверяя экземпляры контейнера в режиме отладки

Следующие работы в Weblogic 12.1.3:

      import org.apache.commons.lang3.reflect.FieldUtils;
      import javax.servlet.Filter;

      [...]

      @Override   
      public void doFilter(ServletRequest request, ServletRespons response, FilterChain chain) throws IOException, ServletException { 
          String path = ((HttpServletRequest) request).getRequestURI();

          if(!bypassSWA(path)){
              swpFilterHandler.doFilter(request, response, chain);

          } else {
              try {
                  ((Filter) (FieldUtils.readField(
                                (FieldUtils.readField(
                                        (FieldUtils.readField(chain, "filters", true)), "last", true)), "item", true)))
                  .doFilter(request, response, chain);
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              }           
          }   
      }
0 голосов
/ 02 ноября 2017

Я столкнулся с той же проблемой, но я вижу ответчик, показанный ниже.

web.xml

 <!-- set this param value for the filter-->
    <init-param>
            <param-name>freePages</param-name>
            <param-value>
            MainFrame.jsp;
            </param-value>
    </init-param>

filter.java

strFreePages = config.getInitParameter("freePages"); //get the exclue pattern from config file
isFreePage(strRequestPage)  //decide the exclude path

таким образомвам не нужно беспокоить конкретный класс Filter.

...