web-dev-qa-db-fra.com

Puis-je exclure des URL concrètes de <url-pattern> à l'intérieur de <filter-mapping>?

Je souhaite appliquer un filtre à béton pour toutes les URL à l’exception d’une seule (par exemple, pour /* sauf pour /specialpath).

Y a-t-il une possibilité de le faire?


exemple de code:

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

L'API de servlet standard ne prend pas en charge cette fonctionnalité. Vous pouvez utiliser un filtre d'URL de réécriture semblable à celui de celui de Tuckey (qui ressemble beaucoup à mod_rewrite d'Apache HTTPD), ou ajouter une vérification dans la méthode doFilter() du filtre à l'écoute sur /*.

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

Si nécessaire, vous pouvez spécifier les chemins à ignorer en tant que init-param du filtre afin que vous puissiez le contrôler dans le web.xml de toute façon. Vous pouvez l'obtenir dans le filtre comme suit:

private String pathToBeIgnored;

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

Si le filtre fait partie d'une API tierce et que vous ne pouvez donc pas le modifier, mappez-le sur un url-pattern plus spécifique, par exemple. /otherfilterpath/* et créez un nouveau filtre sur /* qui transfère le chemin correspondant au filtre tiers.

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

Pour éviter que ce filtre ne s'appelle lui-même que dans une boucle infinie, vous devez le laisser écouter (dispatch) sur REQUEST uniquement et le filtre tiers sur FORWARD uniquement.

Voir également:

142
BalusC

J'ai utilisé une approche décrite par Eric Daugherty : J'ai créé une servlet spéciale qui répond toujours avec le code 403 et met sa correspondance avant la général.

Fragment de cartographie:

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

Et 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);
    }
}
13
mrzasa

Cette approche fonctionne lorsque vous souhaitez empêcher un certain filtre et tous les suivants. Cela devrait bien fonctionner si vous par exemple. voulez servir du contenu sous forme de ressources statiques dans votre conteneur de servlets au lieu de laisser la logique de votre application (via un filtre comme GuiceFilter):

Mappez le dossier avec vos fichiers de ressources statiques sur le servlet par défaut. Créez un filtre de servlet et mettez-le avant le GuiceFilter dans votre fichier web.xml. Dans votre filtre créé, vous pouvez séparer le transfert de certaines demandes vers GuiceFilter et d’autres directement vers le répartiteur. L'exemple suit ...

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

Malheureusement, si vous souhaitez simplement ignorer une étape de la chaîne de filtrage tout en conservant celles qui suivent, cela ne fonctionnera pas.

6
kvitso

Je ne pense pas que vous puissiez le faire. La seule autre option de configuration consiste à énumérer les chemins que vous souhaitez filtrer. Ainsi, au lieu de /*, vous pouvez en ajouter pour /this/* et /that/*, etc., mais cela ne donnera pas une solution suffisante lorsque vous avez beaucoup de ces chemins.

Ce que vous pouvez faire est d’ajouter un paramètre au filtre fournissant une expression (semblable à une expression régulière) utilisée pour ignorer la fonctionnalité de filtrage pour les chemins correspondants . Le conteneur de servlet appellera toujours votre filtre pour ces URL, mais vous avoir un meilleur contrôle sur la configuration.

Modifier

Maintenant que vous indiquez que vous n’avez aucun contrôle sur le filtre, vous pouvez hériter de ce filtre en appelant des méthodes super dans ses méthodes, sauf lorsque le chemin de l’URL que vous souhaitez ignorer est présent et suivre la chaîne de filtrage comme @BalusC proposée construisez un filtre qui instancie votre filtre et vos délégués dans les mêmes circonstances. Dans les deux cas, les paramètres de filtre incluraient à la fois le paramètre d'expression que vous ajoutez et ceux du filtre dont vous héritez ou que vous déléguez.

L'avantage de la création d'un filtre de délégation (un wrapper) est que vous pouvez ajouter la classe de filtre du filtre enveloppé en tant que paramètre et la réutiliser dans d'autres situations comme celle-ci.

3
rsp

J'ai également dû filtrer en fonction du modèle d'URL (/ {nom_service}/api/stats /) en code Java.

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

Mais c'est bizarre, cette servlet ne supporte pas le modèle d'URL autre que (/ *), cela devrait être un cas très courant pour les API de servlet! 

2
Sindhu

J'ai rencontré le même problème, mais je trouve une réponse montrant ci-dessous.

web.xml

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

filtre.Java

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

de cette façon, vous n'avez pas à harceler la classe de filtres en béton.

0
nelson

Si, pour une raison quelconque, vous ne pouvez pas modifier le mappage de filtre d'origine ("/ *" dans mon cas) et que vous envoyez à un filtre tiers non modifiable, les éléments suivants peuvent vous être utiles:

  • Intercepter le chemin à contourner
  • Passer à et exécuter le dernier anneau de la chaîne de filtres (le servlet lui-même)
  • Le saut est fait par réflexion, inspectant les instances de conteneur en mode débogage 

Les travaux suivants dans 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
robermann