ฉันสามารถยกเว้น URL ที่เป็นรูปธรรมจาก <url-pattern> ภายใน <filter-mapping> ได้หรือไม่


127

ฉันต้องการใช้ตัวกรองคอนกรีตสำหรับ URL ทั้งหมดยกเว้นคอนกรีตหนึ่งตัว (เช่น/*ยกเว้น/specialpath)

มีความเป็นไปได้ที่จะทำเช่นนั้นหรือไม่?


รหัสตัวอย่าง:

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

คำตอบ:


156

Servlet API มาตรฐานไม่รองรับสิ่งอำนวยความสะดวกนี้ คุณอาจต้องการที่จะใช้ทั้งตัวกรองเขียน-URL สำหรับเรื่องนี้เหมือนTuckey หนึ่ง (ซึ่งเป็นที่คล้ายกันมาก Apache HTTPD ของmod_rewrite) หรือการเพิ่มการตรวจสอบในวิธีการของการฟังกรองบนdoFilter()/*

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

คุณสามารถถ้าจำเป็นระบุเส้นทางเพื่อจะละเว้นเป็นinit-paramของตัวกรองเพื่อให้คุณสามารถควบคุมมันในweb.xmlอยู่แล้ว คุณสามารถรับได้ในตัวกรองดังนี้:

private String pathToBeIgnored;

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

หากตัวกรองเป็นส่วนหนึ่งของ API ของบุคคลที่สามและคุณไม่สามารถแก้ไขได้ให้จับคู่กับข้อมูลที่เจาะจงมากขึ้นurl-patternเช่น/otherfilterpath/*และสร้างตัวกรองใหม่/*เพื่อส่งต่อไปยังเส้นทางที่ตรงกับตัวกรองของบุคคลที่สาม

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

เพื่อหลีกเลี่ยงไม่ให้ตัวกรองนี้เรียกตัวเองในวงวนไม่สิ้นสุดคุณต้องปล่อยให้มันฟัง (จัดส่ง) บนREQUESTเท่านั้นและเปิดตัวกรองของบุคคลที่สามFORWARDเท่านั้น

ดูสิ่งนี้ด้วย:


3
ปัญหาของฉันคือตัวกรองไม่ใช่ของฉันมันมาจากไลบรารีคอมโพเนนต์
โรมัน

4
Ypu ควรใช้ตัวกรองไลบรารี compnent และขยายเพื่อเพิ่มรหัสที่คุณต้องการใช้เพื่อทำการยกเว้น
gbtimmon

@BalusC หาก "/ specialpath" เพียงแค่ให้บริการทรัพยากรแบบคงที่เช่น js, css เป็นต้น chain.doFilter () จะทำให้การตอบสนองช้าลงหรือไม่ มีวิธีการให้บริการทรัพยากรโดยตรงโดยไม่ผูกมัดตัวกรองหรือไม่?
BenhurCD

@ BenhurCD: ฉันไม่รู้จริงๆว่าคุณจะคิดเรื่องประสิทธิภาพนี้ได้อย่างไร
BalusC

13

ฉันใช้แนวทางที่Eric Daugherty อธิบายไว้ : ฉันสร้าง servlet พิเศษที่ตอบคำถามด้วยรหัส 403 และวางการแมปไว้ก่อนหน้าทั่วไป

ส่วนการแมป:

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

และคลาส 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

วิธีนี้ใช้ได้ผลเมื่อคุณต้องการป้องกันตัวกรองบางตัวและตัวกรองทั้งหมดต่อไปนี้ ควรทำงานได้ดีถ้าคุณเช่น ต้องการให้บริการเนื้อหาบางส่วนเป็นทรัพยากรแบบคงที่ภายในคอนเทนเนอร์ servlet ของคุณแทนที่จะปล่อยให้ตรรกะของแอปพลิเคชันของคุณ (ผ่านตัวกรองเช่น GuiceFilter):

แม็พโฟลเดอร์กับไฟล์รีซอร์สแบบคงที่ของคุณกับ servlet เริ่มต้น สร้างตัวกรอง servlet และวางไว้หน้า GuiceFilter ใน web.xml ของคุณ ในตัวกรองที่คุณสร้างขึ้นคุณสามารถแยกระหว่างการส่งต่อคำขอบางอย่างไปยัง GuiceFilter และอื่น ๆ โดยตรงไปยังผู้มอบหมายงาน ตัวอย่างดังนี้ ...

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

น่าเสียดายที่หากคุณต้องการข้ามขั้นตอนเดียวในห่วงโซ่ตัวกรองในขณะที่รักษาขั้นตอนต่อไปนี้จะไม่ได้ผล


ฉันพยายามใช้วิธีแก้ปัญหาของคุณ แต่สำหรับไฟล์ที่ฉันใช้ตัวกรองและทำลายโซ่ฉันได้รับข้อผิดพลาดตามมา ข้อยกเว้นที่ไม่ถูกตรวจพบโดยตัวกรอง Static Resource Filter: java.io.FileNotFoundException มีความคิดว่าทำไม?
shamaleyte

ในการตั้งค่าหลายบริบทที่ใช้.getRequestURI()จะแตก (ก่อให้เกิด 404 มีโอกาสมากที่สุด) เพราะ.getRequestDispatcherแก้ไขเมื่อเทียบกับเส้นทางบริบท หากเส้นทางบริบทของคุณเป็น/aดังนั้นในตัวอย่างของคุณ URI คำขอจะเป็น/a/staticและการใช้getRequestDispatcher("/a/static")จะทำให้เกิดการต่อต้าน/a/a/staticแทน แก้ไข: ใช้.getServletPath()แทน.getRequestURI(). ฉันจะส่งการแก้ไขเพื่อแก้ไขปัญหานี้ แต่แค่อยากแสดงความคิดเห็น FYI
Reid

3

ฉันไม่คิดว่าคุณจะทำได้ทางเลือกเดียวในการกำหนดค่าอื่น ๆ คือการระบุเส้นทางที่คุณต้องการกรองดังนั้น/*คุณสามารถเพิ่ม/this/*และ/that/*อื่น ๆแทนคุณได้แต่จะไม่นำไปสู่วิธีแก้ปัญหาที่เพียงพอเมื่อคุณมีจำนวนมาก ของเส้นทางเหล่านั้น

สิ่งที่คุณทำได้คือเพิ่มพารามิเตอร์ให้กับตัวกรองที่ให้นิพจน์ (เช่นนิพจน์ทั่วไป) ซึ่งใช้เพื่อข้ามฟังก์ชันการกรองสำหรับเส้นทางที่ตรงกัน คอนเทนเนอร์ servlet จะยังคงเรียกตัวกรองของคุณสำหรับ url เหล่านั้น แต่คุณจะสามารถควบคุมการกำหนดค่าได้ดีขึ้น

แก้ไข

ตอนนี้ที่คุณพูดถึงคุณไม่สามารถควบคุมตัวกรองได้สิ่งที่คุณทำได้คือรับช่วงจากsuperวิธีการเรียกตัวกรองนั้นในวิธีการของมันยกเว้นเมื่อมีเส้นทาง url ที่คุณต้องการข้ามและทำตามห่วงโซ่ตัวกรองเช่น @BalusC ที่เสนอหรือสร้าง ตัวกรองที่สร้างอินสแตนซ์ตัวกรองของคุณและผู้รับมอบสิทธิ์ภายใต้สถานการณ์เดียวกัน ในทั้งสองกรณีพารามิเตอร์ตัวกรองจะรวมทั้งพารามิเตอร์นิพจน์ที่คุณเพิ่มและพารามิเตอร์ของตัวกรองที่คุณสืบทอดมาหรือมอบหมายให้

ข้อดีของการสร้างตัวกรองการมอบหมาย (wrapper) คือคุณสามารถเพิ่มคลาสตัวกรองของตัวกรองที่ถูกห่อเป็นพารามิเตอร์และใช้ซ้ำในสถานการณ์อื่น ๆ เช่นนี้ได้


3

ฉันยังต้องกรองตามรูปแบบ URL (/ {servicename} / api / stats /) ในโค้ดจาวา

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

แต่มันแปลกประหลาดที่ servlet ไม่รองรับรูปแบบ url นอกเหนือจาก (/ *) นี่ควรเป็นกรณีที่พบบ่อยมากสำหรับ servlet API!


0

ฉันพบปัญหาเดียวกัน แต่พบ anwser แสดงด้านล่าง

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

ด้วยวิธีนี้คุณจะไม่ต้องรบกวนคลาสตัวกรองคอนกรีต


0

หากด้วยเหตุผลใดก็ตามคุณไม่สามารถเปลี่ยนการแมปตัวกรองดั้งเดิม ("/ *" ในกรณีของฉัน) และคุณกำลังส่งไปยังตัวกรองของบุคคลที่สามที่ไม่สามารถเปลี่ยนแปลงได้คุณจะพบว่ามีประโยชน์ดังต่อไปนี้:

  • ขวางเส้นทางที่จะเลี่ยง
  • ข้ามไปและเรียกใช้วงแหวนสุดท้ายของห่วงโซ่ตัวกรอง (ตัวกรองเอง)
  • การข้ามทำได้ผ่านการสะท้อนตรวจสอบอินสแตนซ์คอนเทนเนอร์ในโหมดดีบัก

งานต่อไปนี้ใน 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();
              }           
          }   
      }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.