Posso escludere alcuni URL concreti da <url-pattern> all'interno di <filter-mapping>?


127

Voglio che venga applicato un filtro per calcestruzzo per tutti gli URL ad eccezione di un calcestruzzo (ovvero per /*tranne per /specialpath).

C'è una possibilità per farlo?


codice di esempio:

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

Risposte:


156

L'API Servlet standard non supporta questa funzione. Potresti voler usare un filtro di riscrittura-URL per questo come quello di Tuckey (che è molto simile a quello di Apache HTTPD mod_rewrite) o aggiungere un segno di spunta nel doFilter()metodo di ascolto del filtro /*.

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

Se necessario, puoi specificare i percorsi da ignorare come uno init-paramdei filtri in modo da poterli controllare in web.xmlogni caso. Puoi ottenerlo nel filtro come segue:

private String pathToBeIgnored;

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

Se il filtro fa parte dell'API di terze parti e pertanto non è possibile modificarlo, mapparlo su uno più specifico url-pattern, ad esempio /otherfilterpath/*e creare un nuovo filtro su /*cui inoltrare il percorso corrispondente al filtro di terze parti.

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

Per evitare che questo filtro si chiamerà in un ciclo infinito, è necessario lasciarlo in ascolto (invio) REQUESTsolo e il filtro di terze parti FORWARDsolo.

Guarda anche:


3
Il mio problema è che il filtro non è mio, è dalla libreria dei componenti.
Roman,

4
Ypu dovrebbe prendere il filtro della libreria compnent ed estenderlo per aggiungere il codice che si desidera utilizzare per eseguire le esclusioni.
gbtimmon,

@BalusC Se "/ specialpath" serve solo una risorsa statica come js, css ecc, chain.doFilter () rende la risposta più lenta? Esiste un metodo per servire direttamente la risorsa senza concatenare il filtro?
BenhurCD,

@BenhurCD: Non ho davvero idea di come potresti mai venire a conoscenza di questa preoccupazione per le prestazioni.
BalusC,

13

Ho usato un approccio descritto da Eric Daugherty : ho creato un servlet speciale che risponde sempre con il codice 403 e ho messo la sua mappatura prima di quella generale.

Frammento di mappatura:

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

E la classe servlet:

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

Questo approccio funziona quando si desidera impedire un determinato filtro e tutti i seguenti. Dovrebbe funzionare bene se es. vuoi servire alcuni contenuti come risorse statiche all'interno del tuo servlet container invece di lasciare la logica della tua applicazione (attraverso un filtro come GuiceFilter):

Mappare la cartella con i file di risorse statiche sul servlet predefinito. Crea un filtro servlet e mettilo prima di GuiceFilter nel tuo web.xml. Nel filtro creato, puoi separare tra l'inoltro di alcune richieste a GuiceFilter e altre direttamente al dispatcher. L'esempio segue ...

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

Sfortunatamente se vuoi solo saltare un singolo passo nella catena del filtro mantenendo quelli che seguono, questo non funzionerà.


Ho provato ad andare con la tua soluzione, ma per i file che applico il filtro e rompi la catena, ottengo il seguente errore; Eccezione non rilevata generata dal filtro Filtro risorse statico: java.io.FileNotFoundException. Qualche idea sul perché?
shamaleyte,

Nelle configurazioni multi-contesto, l'utilizzo .getRequestURI()si interromperà (causando molto probabilmente un 404) perché si .getRequestDispatcherrisolve in relazione al percorso di contesto . Se il tuo percorso di contesto è /a, nel tuo esempio l'URI della richiesta sarebbe /a/static, e usando invece getRequestDispatcher("/a/static")lo risolverà /a/a/staticinvece. Correzione: utilizzare .getServletPath()invece di .getRequestURI(). Invierò una modifica per risolvere il problema, ma volevo solo lasciare un commento FYI
Reid,

3

Non credo che tu possa, l'unica altra alternativa di configurazione è quella di enumerare i percorsi che vuoi filtrare, quindi invece di /*aggiungerne alcuni per /this/*ed /that/*ecc., Ma questo non porterà a una soluzione sufficiente quando hai un sacco di quei percorsi.

Quello che puoi fare è aggiungere un parametro al filtro fornendo un'espressione (come un'espressione regolare) che viene usata per saltare la funzionalità del filtro per i percorsi corrispondenti. Il contenitore servlet chiamerà comunque il tuo filtro per questi URL ma avrai un migliore controllo sulla configurazione.

modificare

Ora che dici che non hai alcun controllo sul filtro, ciò che potresti fare è ereditare da quel filtro chiamando i supermetodi nei suoi metodi tranne quando è presente il percorso dell'URL che vuoi saltare e segui la catena di filtri come @BalusC proposto, oppure costruisci un filtro che crea un'istanza del filtro e dei delegati nelle stesse circostanze. In entrambi i casi i parametri di filtro includeranno sia il parametro di espressione che aggiungi sia quelli del filtro da cui erediti o deleghi.

Il vantaggio di creare un filtro delegante (un wrapper) è che puoi aggiungere la classe di filtro del filtro wrapped come parametro e riutilizzarla in altre situazioni come questa.


3

Ho anche dovuto filtrare in base al modello di URL (/ {nome servizio} / api / stats /) nel codice java.

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

Ma è bizzarro, quel servlet non supporta il pattern url diverso da (/ *), questo dovrebbe essere un caso molto comune per le API servlet!


0

Ho riscontrato lo stesso problema, ma trovo una risposta che mostra di seguito.

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

in questo modo non è necessario molestare la classe Filter concreta.


0

Se per qualsiasi motivo non è possibile modificare la mappatura del filtro originale ("/ *" nel mio caso) e si sta inviando un filtro di terze parti immutabile, è possibile trovare quanto segue:

  • Intercetta il percorso da bypassare
  • Passa a ed esegue l'ultimo anello della catena del filtro (il servlet stesso)
  • Il salto viene eseguito tramite reflection, ispezionando le istanze del contenitore in modalità debug

Quanto segue funziona in 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();
              }           
          }   
      }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.