<filter-mapping> 내부의 <url-pattern>에서 구체적인 URL을 제외 할 수 있습니까?


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

표준 서블릿 API는이 기능을 지원하지 않습니다. Tuckey 와 유사한 rewrite-URL 필터를 사용하거나 (아파치 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");
}

필터는 제 3 자 API의 일부이며 따라서 당신은보다 구체적인에서 매핑, 수정할 수없는 경우 url-pattern, 예를 들어, /otherfilterpath/*및에 새로운 필터를 생성 /*하는 앞으로 제 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);
}

이 필터가 무한 루프에서 자신을 호출하지 않도록하려면 필터 REQUEST만 수신하고 (제외) 필터 를 써야 FORWARD합니다.

또한보십시오:


3
내 문제는 필터가 내 것이 아니라 구성 요소 라이브러리에서 가져온 것입니다.
Roman

4
Ypu는 제외를 수행하는 데 사용할 코드를 추가하기 위해 유능한 라이브러리 필터를 가져와 확장해야합니다.
gbtimmon

@BalusC 만약 "/ specialpath"가 js, css 등과 같은 정적 리소스를 제공한다면 chain.doFilter ()는 응답을 느리게합니까? 필터를 연결하지 않고 직접 리소스를 제공하는 방법이 있습니까?
BenhurCD

@ BenhurCD : 나는이 성능 문제에 어떻게 대처할 수 있는지 전혀 모른다.
BalusC

13

Eric Daugherty가 설명 한 접근 방식을 사용했습니다 . 항상 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>

그리고 서블릿 클래스 :

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

이 방법은 특정 필터와 다음 필터를 모두 방지하려는 경우에 작동합니다. 예를 들어 잘 작동합니다. GuiceFilter와 같은 필터를 통해 응용 프로그램 논리를 허용하지 않고 서블릿 컨테이너 내에서 일부 내용을 정적 리소스로 제공하려고합니다.

정적 자원 파일이있는 폴더를 기본 서블릿에 맵핑하십시오. 서블릿 필터를 만들어 web.xml에서 GuiceFilter 앞에 놓습니다. 생성 된 필터에서 일부 요청을 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");
    }
}

불행히도 다음 단계를 유지하면서 필터 체인에서 한 단계를 건너 뛰려면 작동하지 않습니다.


귀하의 솔루션을 시도했지만 필터를 적용하고 체인을 끊는 파일의 경우 다음과 같은 오류가 발생합니다. 필터 정적 자원 필터에 의해 발생 된 포착되지 않은 예외 : java.io.FileNotFoundException. 왜 그런지 알아?
shamaleyte 2016 년

다중 콘텍스트 설정에 사용 .getRequestURI()(404 대부분의 원인) 분해되므로 .getRequestDispatcher리졸 컨텍스트 경로에 대하여 . 컨텍스트 경로가 /a인 경우 예제에서 요청 URI는 /a/static이고를 사용 getRequestDispatcher("/a/static")하면 /a/a/static대신 URI가 해결 됩니다. 수정 : .getServletPath()대신 사용하십시오 .getRequestURI(). 이 문제를 해결하기 위해 수정 사항을 제출하지만 의견을 남기고 싶었습니다. FYI
Reid

3

나는 당신이 할 수있는 유일한 다른 구성 대안 그래서 대신에, 당신은 필터링하려는 경로를 열거하는 것입니다 생각하지 않는 /*몇 가지를 추가 할 수 있습니다 당신 /this/*/that/*등,하지만 당신은 많이있을 때 충분한 솔루션으로 이어질하지 않습니다 그 길의.

일치하는 경로에 대한 필터 기능을 건너 뛰는 데 사용되는 표현식 (예 : 정규식)을 제공하는 매개 변수를 필터에 추가하면됩니다. 서블릿 컨테이너는 여전히 해당 URL에 대한 필터를 호출하지만 구성을보다 잘 제어 할 수 있습니다.

편집하다

필터에 대한 제어 권한이 없다고 언급 super했으므로 건너 뛸 URL 경로가 있고 @BalusC 제안 된 필터 체인을 따르는 경우를 제외하고 메소드에서 해당 필터 호출 메소드에서 상속 하거나 빌드 할 수 있습니다. 동일한 상황에서 필터를 인스턴스화하고 위임하는 필터. 두 경우 모두 필터 매개 변수에는 추가 한 식 매개 변수와 상속하거나 위임 한 필터의 매개 변수가 모두 포함됩니다.

위임 필터 (래퍼)를 만들면 래핑 된 필터의 필터 클래스를 매개 변수로 추가하고 이와 같은 다른 상황에서 재사용 할 수 있다는 장점이 있습니다.


3

또한 Java 코드의 URL 패턴 (/ {servicename} / api / stats /)을 기준으로 필터링해야했습니다.

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

그러나 그 기괴한 서블릿은 (/ *) 이외의 URL 패턴을 지원하지 않습니다. 이것은 서블릿 API의 경우 매우 일반적인 경우입니다!


0

같은 문제가 발생했지만 아래에 답변이 표시됩니다.

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.