Могу ли я исключить некоторые конкретные URL-адреса изнутри?


Я хочу, чтобы какой-то конкретный фильтр применялся для всех 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 112

7 ответов:

стандартный сервлет API не поддерживает этот объект. Вы можете либо использовать фильтр rewrite-URL для этого, как таки вот!--15--> (который сильно похож на 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 только.

посмотреть также:

я использовал подход описанный Эриком Догерти: Я создал специальный сервлет, который всегда отвечает с кодом 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);
    }
}

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

сопоставьте папку со статическими файлами ресурсов с сервлетом по умолчанию. Создайте фильтр сервлета и поместите его до GuiceFilter в вашем интернете.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.класс

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");
    }
}

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

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

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

Edit

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

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

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

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

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

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

web.xml

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

фильтр.java

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

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

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

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

следующие работы в 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();
              }           
          }   
      }