139 votes

Puis-je exclure certaines urls concrètes de <url-pattern> dans <filter-mapping> ?

Je veux qu'un filtre concret soit appliqué pour toutes les urls sauf pour une concrète (c'est-à-dire 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>

172voto

BalusC Points 498232

L'API standard des servlets ne prend pas en charge cette fonction. Pour cela, vous pouvez utiliser un filtre rewrite-URL, par exemple Celui de Tuckey (qui est très similaire à l'Apache HTTPD's mod_rewrite ), ou pour ajouter une vérification dans le doFilter() du filtre qui é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.
}

Vous pouvez si nécessaire spécifier les chemins à ignorer comme un init-param du filtre afin que vous puissiez le contrôler dans le cadre de la 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 de l'API d'une tierce partie et que vous ne pouvez donc pas le modifier, mappez-le sur une adresse plus spécifique url-pattern par exemple /otherfilterpath/* et créer un nouveau filtre sur /* qui renvoie vers le chemin correspondant au filtre de la tierce partie.

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 dans une boucle infinie, vous devez le laisser écouter (dispatcher) sur REQUEST seulement et le filtre tiers sur FORWARD seulement.

Voir aussi :

3 votes

Mon problème est que le filtre n'est pas le mien, il provient de la bibliothèque des composants.

4 votes

Vous devez prendre le filtre de la bibliothèque des composants et l'étendre afin d'ajouter le code que vous souhaitez utiliser pour effectuer les exclusions.

0 votes

@BalusC Si le "/specialpath" sert juste une ressource statique comme js, css etc, est-ce que chain.doFilter() rend la réponse plus lente ? Existe-t-il une méthode pour servir la ressource directement sans enchaîner le filtre ?

15voto

mrzasa Points 1589

J'ai utilisé une approche décrit par Eric Daugherty : J'ai créé une servlet spéciale qui répond toujours avec le code 403 et j'ai mis son mapping avant celui du 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 de 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);
    }
}

12voto

kvitso Points 81

Cette approche fonctionne lorsque vous voulez empêcher un certain filtre et tous les suivants. Elle devrait bien fonctionner si vous voulez, par exemple, servir du contenu en tant que ressources statiques dans votre conteneur de servlets au lieu de laisser votre logique d'application (à travers un filtre comme GuiceFilter) :

Mettez en correspondance le dossier contenant vos fichiers de ressources statiques avec le servlet par défaut. Créez un filtre de servlet et mettez-le avant le GuiceFilter dans votre web.xml. Dans le filtre que vous avez créé, vous pouvez séparer le transfert de certaines requêtes vers le GuiceFilter et d'autres directement vers le dispatcher. Voici un exemple...

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 sauter une étape de la chaîne de filtrage tout en conservant celles qui suivent, cela ne fonctionnera pas.

0 votes

J'ai essayé de suivre votre solution, mais pour les fichiers que j'applique le filtre et que je casse la chaîne, j'obtiens l'erreur suivante : Uncaught exception thrown by filter Static Resource Filter : java.io.FileNotFoundException. Une idée de la raison ?

1 votes

Dans les configurations multi-contexte, l'utilisation de .getRequestURI() se brisera (provoquant un 404 très probablement) parce que .getRequestDispatcher résout relatif au chemin du contexte . Si le chemin du contexte est /a alors, dans votre exemple, l'URI de la demande serait le suivant /a/static et en utilisant getRequestDispatcher("/a/static") le fera résoudre contre /a/a/static au lieu de. Correction : utiliser .getServletPath() au lieu de .getRequestURI() . Je vais soumettre une modification pour corriger cela, mais je voulais juste laisser un commentaire pour info.

3voto

Sindhu Points 696

J'avais également besoin de filtrer sur la base du modèle d'URL (/{servicename}/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 que la servlet ne supporte pas de modèle d'url autre que (/*), Cela devrait être un cas très commun pour les API de servlet !

3voto

rsp Points 14367

Je ne pense pas que vous puissiez, la seule autre alternative de configuration est d'énumérer les chemins que vous voulez filtrer, donc au lieu de /* vous pourriez en ajouter pour /this/* et /that/* etc, mais cela ne mènera pas à une solution suffisante lorsque vous avez beaucoup de ces chemins.

Ce que vous pouvez faire, c'est ajouter un paramètre au filtre fournissant une expression (comme une expression régulière) qui est utilisée pour ignorer la fonctionnalité de filtrage pour les chemins correspondants. Le conteneur de servlets appellera toujours votre filtre pour ces url, mais vous aurez un meilleur contrôle sur la configuration.

Modifier

Maintenant que vous mentionnez que vous n'avez aucun contrôle sur le filtre, ce que vous pourriez faire est soit d'hériter de ce filtre en appelant super dans ses méthodes sauf lorsque le chemin url que vous voulez sauter est présent et suivre la chaîne de filtres comme @BalusC l'a proposé, ou construire un filtre qui instancie votre filtre et délègue dans les mêmes circonstances. Dans les deux cas, les paramètres du filtre comprendraient à la fois le paramètre d'expression que vous ajoutez et ceux du filtre dont vous héritez ou auquel vous déléguez.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X