Czy mogę wykluczyć niektóre konkretne adresy URL z <url-pattern> wewnątrz <filter-mapping>?


128

Chcę, aby jakiś konkretny filtr był stosowany do wszystkich adresów URL z wyjątkiem jednego konkretnego (tj. Z /*wyjątkiem /specialpath).

Czy jest taka możliwość?


przykładowy kod:

<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>

Odpowiedzi:


158

Standardowe Servlet API nie obsługuje tej funkcji. Możesz też użyć filtru przepisywania URL do tego jak jeden Tuckey za (co jest znacznie podobny Apache HTTPD użytkownika mod_rewrite), lub dodać czek w doFilter()sposobie słuchania filtrować /*.

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.
}

W razie potrzeby możesz określić ścieżki, które mają być zignorowane, jako element init-paramfiltru, aby web.xmlmimo wszystko można było nim sterować . Możesz go pobrać w filtrze w następujący sposób:

private String pathToBeIgnored;

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

Jeśli filtr jest częścią interfejsu API innej firmy i dlatego nie możesz go zmodyfikować, zmapuj go na bardziej szczegółowe url-pattern, np. /otherfilterpath/*I utwórz nowy filtr, w /*którym przekierowuje do ścieżki pasującej do filtra strony trzeciej.

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

Aby uniknąć tego, że ten filtr będzie wywoływał siebie w nieskończonej pętli, musisz pozwolić mu tylko nasłuchiwać (wysyłać) REQUESTi włączać FORWARDtylko filtr strony trzeciej .

Zobacz też:


3
Mój problem polega na tym, że filtr nie jest mój, pochodzi z biblioteki komponentów.
Roman

4
Ypu powinien wziąć filtr biblioteki komponentowej i rozszerzyć go, aby dodać kod, którego chcesz użyć do wykonania wykluczeń.
gbtimmon

@BalusC Jeśli „/ specialpath” obsługuje tylko statyczny zasób, taki jak js, css itp., Czy chain.doFilter () spowalnia odpowiedź? Czy istnieje metoda bezpośredniego udostępniania zasobów bez łączenia filtra w łańcuch?
BenhurCD,

@BenhurCD: Naprawdę nie mam pojęcia, jak mógłbyś kiedykolwiek podejść do tego problemu.
BalusC,

14

Zastosowałem podejście opisane przez Erica Daugherty'ego : stworzyłem specjalny serwlet, który zawsze odpowiada kodem 403 i stawiam jego mapowanie przed ogólnym.

Fragment mapowania:

  <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>

I klasa serwletów:

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

10

To podejście działa, gdy chcesz zapobiec określonemu filtrowi i wszystkim kolejnym. Powinien dobrze działać, jeśli np. chcesz udostępniać część treści jako statyczne zasoby w swoim kontenerze serwletów, zamiast pozwalać logice aplikacji (przez filtr taki jak GuiceFilter):

Zamapuj folder ze statycznymi plikami zasobów na domyślny serwlet. Utwórz filtr serwletów i umieść go przed GuiceFilter w swoim web.xml. W utworzonym filtrze możesz oddzielić przekazywanie niektórych żądań do GuiceFilter, a innych bezpośrednio do dyspozytora. Oto przykład ...

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

Niestety, jeśli chcesz po prostu pominąć jeden krok w łańcuchu filtrów, zachowując następujące po nim, to nie zadziała.


Próbowałem iść z twoim rozwiązaniem, ale dla plików, które stosuję filtr i zrywam łańcuch, otrzymuję następujący błąd; Niezłapany wyjątek zgłoszony przez filtr Statyczny filtr zasobów: java.io.FileNotFoundException. Każdy pomysł, dlaczego?
shamaleyte

W konfiguracjach z wieloma kontekstami użycie .getRequestURI()zakończy się niepowodzeniem (najprawdopodobniej powodując błąd 404), ponieważ zostanie .getRequestDispatcherrozwiązany względem ścieżki kontekstu . Jeśli twoja ścieżka kontekstu to /a, to w twoim przykładzie identyfikator URI żądania będzie taki /a/static, a użycie getRequestDispatcher("/a/static")spowoduje /a/a/staticzamiast tego rozwiązanie . Poprawka: użyj .getServletPath()zamiast .getRequestURI(). Prześlę zmianę, aby to naprawić, ale chciałem tylko zostawić komentarz Do Twojej wiadomości
Reid

3

Myślę, że nie możesz, jedyną inną alternatywą konfiguracji jest wyliczenie ścieżek, które chcesz filtrować, więc zamiast tego /*możesz dodać kilka dla /this/*i /that/*itp., Ale to nie doprowadzi do wystarczającego rozwiązania, gdy masz dużo tych ścieżek.

To, co możesz zrobić, to dodać parametr do filtru, dostarczając wyrażenie (takie jak wyrażenie regularne), które jest używane do pomijania funkcji filtru dla dopasowanych ścieżek. Kontener serwletów nadal będzie wywoływał filtr dla tych adresów URL, ale będziesz mieć lepszą kontrolę nad konfiguracją.

Edytować

Teraz, gdy wspomniałeś, że nie masz kontroli nad filtrem, możesz albo dziedziczyć z tego filtru wywołujące supermetody w jego metodach, z wyjątkiem sytuacji, gdy istnieje ścieżka adresu URL, który chcesz pominąć, i postępować zgodnie z łańcuchem filtrów, takim jak proponowany @BalusC, lub zbudować filtr, który tworzy instancję filtru i delegatów w tych samych okolicznościach. W obu przypadkach parametry filtru obejmowałyby zarówno dodawany parametr wyrażenia, jak i filtr, z którego dziedziczono lub do którego delegowano.

Zaletą tworzenia filtru delegującego (opakowania) jest to, że można dodać klasę filtru opakowanego filtru jako parametr i użyć go ponownie w innych sytuacjach, takich jak ta.


3

Musiałem też filtrować na podstawie wzorca adresu URL (/ {nazwa usługi} / api / stats /) w kodzie java.

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

Ale to dziwne, że serwlet nie obsługuje wzorca adresu URL innego niż (/ *). Powinien to być bardzo częsty przypadek dla API serwletów!


0

Napotkałem ten sam problem, ale poniżej znajduje się odpowiedź.

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

w ten sposób nie musisz nękać konkretnej klasy Filter.


0

Jeśli z jakiegoś powodu nie możesz zmienić oryginalnego mapowania filtru („/ *” w moim przypadku) i wysyłasz do niezmiennego filtra innej firmy, przydatne mogą być następujące elementy:

  • Przechwyć ścieżkę, którą chcesz ominąć
  • Przejdź do ostatniego pierścienia łańcucha filtrów (sam serwlet) i wykonaj go
  • Pomijanie odbywa się poprzez odbicie, sprawdzanie instancji kontenera w trybie debugowania

Następujące prace w 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

Byłem w stanie poradzić sobie z tym wiosną 2 w następujący sposób

 private boolean isInPath(ServletRequest request) {
   String PATH_TO_VALIDATE = "/path/";
   String path = ((HttpServletRequest) request).getRequestURI();
   return path != null && path.toLowerCase().contains(PATH_TO_VALIDATE);
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.