Чи можу я виключити деякі конкретні URL-адреси з <url-pattern> всередині <фільтра- карти>?


127

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

Відповіді:


156

Стандартний API сервлетів не підтримує цей інструмент. Ви можете або використати фільтр перезаписати URL-адрес для подібного типу Tuckey (який дуже схожий на HTTPD Apache 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лише.

Дивитися також:


3
Моя проблема полягає в тому, що фільтр не мій, це з бібліотеки компонентів.
Роман

4
Ypu повинен взяти фільтр бібліотеки компенсантів і розширити його, щоб додати код, який потрібно використовувати для виконання виключень.
gbtimmon

@BalusC Якщо "/ specialpath" просто обслуговує статичний ресурс, такий як js, css тощо, чи робить ланцюжок.doFilter () повільніше? Чи існує спосіб подачі ресурсу безпосередньо без прив’язки фільтра?
BenhurCD

@BenhurCD: Я насправді не маю уявлення, як ви могли коли-небудь підійти до цієї проблеми.
BalusC

13

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

9

Цей підхід працює, коли ви хочете запобігти певний фільтр та всі наступні. Це повинно добре працювати, якщо ви, наприклад. хочете подавати деякий вміст як статичні ресурси в контейнері сервлетів, а не впускати логіку програми (через фільтр, як 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");
    }
}

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


Я спробував піти з вашим рішенням, але для файлів, до яких я застосовую фільтр і розриваю ланцюг, я отримую помилку слідування; Невиконаний виняток, кинутий фільтром Статичний фільтр ресурсів: java.io.FileNotFoundException. Будь-яка ідея чому?
shamaleyte

У налаштуваннях кількох контекстів використання .getRequestURI()буде перервано (спричиняючи 404, швидше за все), оскільки .getRequestDispatcherвирішується відносно шляху до контексту . Якщо ваш контекстний шлях є /a, то у вашому прикладі буде URI запиту /a/static, і використання getRequestDispatcher("/a/static")його призведе до вирішення /a/a/staticнатомість. Виправлення: використовувати .getServletPath()замість .getRequestURI(). Я надішлю редагування, щоб виправити це, але просто хотів залишити коментар FYI
Reid

3

Я не думаю, що ви можете, єдиною іншою альтернативою конфігурації є перерахування контурів, які ви хочете відфільтрувати, так що замість цього /*ви можете додати дещо для /this/*і /that/*т. Д., Але це не призведе до достатнього рішення, коли у вас є багато цих стежок.

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

Редагувати

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

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


3

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

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

Але химерно, що сервлет не підтримує шаблон URL-адреси, крім (/ *), це має бути дуже поширеним випадком для API сервлетів!


0

Я зіткнувся з тим же питанням, але нижче виявляю прикмет.

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.


0

Якщо з будь-якої причини ви не можете змінити оригінальне відображення фільтра ("/ *" в моєму випадку), і ви відправляєте на незмінний сторонній фільтр, ви можете знайти корисне наступне:

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

Наступні роботи в 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();
              }           
          }   
      }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.