Tôi có thể loại trừ một số url cụ thể khỏi <url-mẫu> bên trong <ánh xạ bộ lọc> không?


127

Tôi muốn một số bộ lọc bê tông được áp dụng cho tất cả các url trừ một bê tông (ví dụ: /*ngoại trừ /specialpath).

Có khả năng để làm điều đó?


mã mẫu:

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

Câu trả lời:


156

API Servlet tiêu chuẩn không hỗ trợ cơ sở này. Bạn có thể muốn sử dụng bộ lọc URL viết lại cho bộ lọc này giống như bộ lọc của Cuckey (tương tự như HTTP HTTPD mod_rewrite) hoặc thêm một kiểm tra trong doFilter()phương thức của Bộ lọc lắng nghe /*.

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

Bạn có thể nếu cần chỉ định các đường dẫn sẽ bị bỏ qua như một init-parambộ lọc để bạn có thể kiểm soát nó trong web.xmlmọi trường hợp. Bạn có thể lấy nó trong bộ lọc như sau:

private String pathToBeIgnored;

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

Nếu bộ lọc là một phần của API của bên thứ 3 và do đó bạn không thể sửa đổi nó, thì hãy ánh xạ nó theo một cách cụ thể hơn url-pattern, ví dụ /otherfilterpath/*và tạo một bộ lọc mới /*để chuyển tiếp tới đường dẫn khớp với bộ lọc của bên thứ 3.

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

Để tránh điều đó, bộ lọc này sẽ tự gọi nó trong một vòng lặp vô hạn, bạn chỉ cần để nó lắng nghe (công văn) REQUESTvà bộ lọc bên thứ 3 FORWARDchỉ.

Xem thêm:


3
Vấn đề của tôi là bộ lọc không phải của tôi, nó là từ thư viện thành phần.
La Mã

4
Ypu nên lấy bộ lọc thư viện compnent và mở rộng nó để thêm mã bạn muốn sử dụng để thực hiện các loại trừ.
gbtimmon

@BalusC Nếu "/ Specialpath" chỉ phục vụ tài nguyên tĩnh như js, css, v.v., chain.doFilter () có làm cho phản hồi chậm hơn không? Có một phương pháp để phục vụ tài nguyên trực tiếp mà không cần xâu chuỗi bộ lọc?
BenhurCD

@BenhurCD: Tôi thực sự không biết làm thế nào bạn có thể đến với mối quan tâm hiệu suất này.
BalusC

13

Tôi đã sử dụng một cách tiếp cận được mô tả bởi Eric Daugherty : Tôi đã tạo ra một servlet đặc biệt luôn trả lời bằng mã 403 và đặt ánh xạ của nó trước mã chung.

Đoạn bản đồ:

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

Và lớp 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

Cách tiếp cận này hoạt động khi bạn muốn ngăn chặn một bộ lọc nhất định và tất cả các bộ lọc sau. Nó sẽ hoạt động tốt nếu bạn ví dụ. muốn phân phát một số nội dung dưới dạng tài nguyên tĩnh trong vùng chứa servlet của bạn thay vì để logic ứng dụng của bạn (thông qua bộ lọc như GuiceFilter):

Ánh xạ thư mục với các tệp tài nguyên tĩnh của bạn vào servlet mặc định. Tạo bộ lọc servlet và đặt nó trước GuiceFilter trong tệp web của bạn. Trong bộ lọc đã tạo của bạn, bạn có thể tách biệt giữa việc chuyển tiếp một số yêu cầu tới GuiceFilter và các yêu cầu khác trực tiếp đến bộ điều phối. Ví dụ sau ...

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

Thật không may nếu bạn chỉ muốn bỏ qua một bước duy nhất trong chuỗi bộ lọc trong khi vẫn giữ những bước tiếp theo, điều này sẽ không hoạt động.


Tôi đã cố gắng đi với giải pháp của bạn, nhưng đối với các tệp mà tôi áp dụng bộ lọc và phá vỡ chuỗi, tôi gặp lỗi theo dõi; Uncaught ngoại lệ được ném bởi bộ lọc Bộ lọc tài nguyên tĩnh: java.io.FileNotFoundException. Bất cứ ý tưởng tại sao?
shamaleyte

Trong các thiết lập đa ngữ cảnh, việc sử dụng .getRequestURI()sẽ phá vỡ (rất có thể gây ra 404) vì .getRequestDispatchergiải quyết liên quan đến đường dẫn ngữ cảnh . Nếu đường dẫn ngữ cảnh của bạn là /a, thì trong ví dụ của bạn, URI yêu cầu sẽ là /a/staticvà việc sử dụng getRequestDispatcher("/a/static")sẽ khiến nó giải quyết /a/a/staticthay thế. Khắc phục: sử dụng .getServletPath()thay vì .getRequestURI(). Tôi sẽ gửi bản chỉnh sửa để sửa lỗi này, nhưng chỉ muốn để lại nhận xét FYI
Reid

3

Tôi không nghĩ bạn có thể, cách thay thế cấu hình duy nhất khác là liệt kê các đường dẫn mà bạn muốn được lọc, vì vậy thay vì /*bạn có thể thêm một số cho /this/*/that/*v.v., nhưng điều đó sẽ không dẫn đến một giải pháp đủ khi bạn có nhiều của những con đường đó.

Những gì bạn có thể làm là thêm một tham số vào bộ lọc cung cấp một biểu thức (như biểu thức chính quy) được sử dụng để bỏ qua chức năng bộ lọc cho các đường dẫn khớp. Bộ chứa servlet vẫn sẽ gọi bộ lọc của bạn cho các url đó nhưng bạn sẽ kiểm soát tốt hơn cấu hình.

Biên tập

Bây giờ bạn đề cập rằng bạn không có quyền kiểm soát bộ lọc, những gì bạn có thể làm là kế thừa từ supercác phương thức gọi bộ lọc đó trong các phương thức của nó trừ khi có đường dẫn url bạn muốn bỏ qua và theo chuỗi bộ lọc như @BalusC đề xuất hoặc xây dựng một bộ lọc khởi tạo bộ lọc của bạn và các đại biểu trong cùng hoàn cảnh. Trong cả hai trường hợp, các tham số bộ lọc sẽ bao gồm cả tham số biểu thức bạn thêm và các tham số của bộ lọc mà bạn kế thừa từ hoặc ủy quyền.

Ưu điểm của việc xây dựng bộ lọc ủy nhiệm (trình bao bọc) là bạn có thể thêm lớp bộ lọc của bộ lọc được bọc làm tham số và sử dụng lại nó trong các tình huống khác như trường hợp này.


3

Tôi cũng phải lọc dựa trên mẫu URL (/ {tên dịch vụ} / api / stats /) trong mã java.

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

Nhưng thật kỳ lạ, servlet đó không hỗ trợ mẫu url khác với (/ *), Đây có thể là trường hợp rất phổ biến đối với API của servlet!


0

Tôi đã gặp vấn đề tương tự, nhưng tôi tìm thấy một anwser hiển thị dưới đây.

web.xml

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

bộ lọc.java

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

bằng cách này, bạn không phải quấy rối lớp Lọc cụ thể.


0

Nếu vì bất kỳ lý do gì, bạn không thể thay đổi ánh xạ bộ lọc gốc ("/ *" trong trường hợp của tôi) và bạn đang gửi đến bộ lọc bên thứ ba không thể thay đổi, bạn có thể tìm thấy những điều hữu ích sau:

  • Đánh chặn con đường bị bỏ qua
  • Bỏ qua và thực hiện vòng cuối cùng của chuỗi bộ lọc (chính servlet)
  • Việc bỏ qua được thực hiện thông qua sự phản chiếu, kiểm tra các trường hợp container trong chế độ gỡ lỗi

Các công việc sau đây trong 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();
              }           
          }   
      }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.