<filter-mapping> içindeki bazı somut url'leri <url-pattern> dışında bırakabilir miyim?


127

Bir beton dışındaki tüm url'ler için bazı beton filtrenin uygulanmasını istiyorum (yani /*hariç /specialpath).

Bunu yapma imkanı var mı?


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

Yanıtlar:


156

Standart Servlet API bu tesisi desteklemiyor. Bunun için Tuckey'inki gibi (Apache HTTPD'lerine çok benzeyen) bir URL yeniden yazma filtresi kullanmak mod_rewriteveya doFilter()Filtre dinleme yöntemine bir kontrol eklemek isteyebilirsiniz /*.

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

Gerekirse init-param, web.xmlyine de kontrol edebilmeniz için yok sayılacak yolları filtrenin bir parçası olarak belirtebilirsiniz . Aşağıdaki gibi filtreden alabilirsiniz:

private String pathToBeIgnored;

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

Filtre 3. parti API bir parçasıdır ve bu nedenle daha sonra daha belirgin bir üzerinde eşlemek, değişiklik yapamıyorsanız url-pattern, örneğin /otherfilterpath/*ve yeni bir filtre oluşturmak /*hangi ileri 3. parti filtreyle eşleşen yola.

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

Bu filtrenin kendisini sonsuz bir döngüde çağırmasını önlemek için, REQUESTyalnızca dinlemesine (dağıtmasına) ve yalnızca 3. taraf filtresine izin vermeniz gerekir FORWARD.

Ayrıca bakınız:


3
Benim sorunum, filtre benim değil, bileşen kitaplığından.
Roman

4
Ypu, dışlamaları gerçekleştirmek için kullanmak istediğiniz kodu eklemek için bileşen kitaplık filtresini almalı ve genişletmelidir.
gbtimmon

@BalusC "/ specialpath" js, css vb. Gibi statik bir kaynağa hizmet ediyorsa, chain.doFilter () yanıtı yavaşlatır mı? Kaynağa filtreyi zincirlemeden doğrudan hizmet etmenin bir yöntemi var mı?
BenhurCD

@BenhurCD: Bu performans sorununu nasıl çözebileceğiniz konusunda hiçbir fikrim yok.
BalusC

13

Eric Araujo tarafından anlatılan bir yaklaşımı kullandım : Her zaman 403 koduyla cevap veren ve eşlemesini genel olanın önüne koyan özel bir sunucu uygulaması yarattım.

Eşleme parçası:

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

Ve servlet sınıfı:

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

Bu yaklaşım, belirli bir filtreyi ve aşağıdakilerin tümünü önlemek istediğinizde işe yarar. Örneğin, eğer iyi çalışmalıdır. uygulama mantığınıza izin vermek yerine (GuiceFilter gibi bir filtre aracılığıyla) bazı içeriği sunucu uygulaması kapsayıcınızda statik kaynaklar olarak sunmak istiyorsanız:

Statik kaynak dosyalarınızın bulunduğu klasörü varsayılan sunucu uygulamasına eşleyin. Bir sunucu uygulaması filtresi oluşturun ve web.xml'nizdeki GuiceFilter'in önüne koyun . Oluşturduğunuz filtrede, bazı istekleri GuiceFilter'e ve diğerlerini doğrudan dağıtıcıya iletmek arasında ayrım yapabilirsiniz. Örnek aşağıdaki ...

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

Ne yazık ki, takip edenleri korurken filtre zincirinde sadece tek bir adımı atlamak istiyorsanız, bu işe yaramayacaktır.


Çözümünüzle gitmeye çalıştım, ancak filtreyi uyguladığım ve zinciri kırdığım dosyalar için followin hatası alıyorum; Statik Kaynak Filtresi: java.io.FileNotFoundException süzgeci tarafından yakalanmamış istisna atıldı. Herhangi bir fikrin neden?
shamaleyte

Çok bağlamlı kurulumlarda, bağlam yoluna göre çözümlendiğinden kullanımı .getRequestURI()kesilir (büyük olasılıkla 404'e neden olur) . Bağlam yolunuz ise , örneğinizde istek URI'si olur ve kullanmak bunun yerine çözümlenmesine neden olur . Düzeltme: yerine kullanın . Bunu düzeltmek için bir düzenleme göndereceğim, ancak sadece bir yorum bırakmak istedim FYI.getRequestDispatcher/a/a/staticgetRequestDispatcher("/a/static")/a/a/static.getServletPath().getRequestURI()
Reid

3

Yapabileceğinizi sanmıyorum, diğer yapılandırma alternatifi, filtrelenmesini istediğiniz yolları numaralandırmaktır, bu yüzden yerine /*bazılarını /this/*ve /that/*vb. Ekleyebilirsiniz , ancak bu, çok şey olduğunda yeterli bir çözüme yol açmaz bu yollardan.

Yapabileceğiniz şey, eşleşen yollar için filtre işlevini atlamak için kullanılan bir ifade (normal ifade gibi) sağlayan bir parametreyi filtreye eklemektir. Sunucu uygulaması kapsayıcısı yine de bu url'ler için filtrenizi arayacaktır, ancak yapılandırma üzerinde daha iyi kontrole sahip olacaksınız.

Düzenle

Artık filtre üzerinde hiçbir kontrolünüz olmadığından bahsettiğinize göre super, atlamak istediğiniz url yolunun mevcut olması ve @BalusC'nin önerdiği gibi filtre zincirini takip etmeniz dışında, yapabileceğiniz şey, yöntemlerinde o filtreden çağrı yöntemlerinden miras almaktır. aynı koşullar altında filtrenizi ve temsilcilerinizi başlatan bir filtre. Her iki durumda da filtre parametreleri hem eklediğiniz ifade parametresini hem de miras aldığınız veya yetki verdiğiniz filtrenin parametrelerini içerir.

Temsilci filtre (sarıcı) oluşturmanın avantajı, sarılmış filtrenin filtre sınıfını parametre olarak ekleyebilmeniz ve bunun gibi diğer durumlarda yeniden kullanabilmenizdir.


3

Ayrıca java kodundaki URL kalıbına (/ {servicename} / api / stats /) göre filtrelemem gerekiyordu.

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

Ancak bu sunucu uygulaması (/ *) dışında bir url kalıbını desteklemiyor tuhaf, bu, sunucu uygulaması API'leri için çok yaygın bir durum olmalı!


0

Aynı sorunla karşılaştım, ancak aşağıda gösterilen bir yanıtlayıcı buldum.

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

bu şekilde beton Filtre sınıfını taciz etmek zorunda kalmazsınız.


0

Herhangi bir nedenle orijinal filtre eşlemesini (benim durumumda "/ *") değiştiremiyorsanız ve değiştirilemez bir üçüncü taraf filtreye gönderiyorsanız, aşağıdakileri faydalı bulabilirsiniz:

  • Atlanacak yolu durdurun
  • Filtre zincirinin son halkasına atlayın ve yürütün (sunucu uygulamasının kendisi)
  • Atlama, kapsayıcı örneklerini hata ayıklama modunda inceleyerek yansıtma yoluyla yapılır.

Aşağıdaki Weblogic 12.1.3'te çalışır:

      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();
              }           
          }   
      }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.