<filter-mapping>内の<url-pattern>からいくつかの具体的なURLを除外できますか?


127

コンクリートフィルターを1つのコンクリートを除くすべての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のフィルター(Apache HTTPDとよく似ているmod_rewrite)のようなrewrite-URLフィルターを使用するか、を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は、除外の実行に使用するコードを追加するために、適切なライブラリフィルターを取得して拡張する必要があります。
gbtimmon、

@BalusC「/ specialpath」がjs、cssなどの静的リソースを提供するだけの場合、chain.doFilter()は応答を遅くしますか?フィルターをチェーンせずにリソースを直接提供する方法はありますか?
BenhurCD、2014

@BenhurCD:このパフォーマンスの問題をどのようにして解決できるか、私にはまったくわかりません。
BalusC 2014

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

残念ながら、後続のステップを維持しながらフィルターチェーンの1つのステップだけをスキップしたい場合、これは機能しません。


私はあなたの解決策を試そうとしましたが、フィルターを適用してチェーンを切断したファイルについて、フォローインエラーが発生しました。フィルター静的リソースフィルターによってスローされたキャッチされない例外:java.io.FileNotFoundException。なぜか?
shamaleyte 2015年

マルチコンテキストセットアップでは、コンテキストパス基準に解決される.getRequestURI()ため、使用すると404が発生します。コンテキストパスがの場合、例では要求URIはとなり、使用すると、代わりに解決されます。修正:の代わりに使用してください。私はこれを修正するために編集を提出しますが、コメントを残したいと思いますFYI.getRequestDispatcher/a/a/staticgetRequestDispatcher("/a/static")/a/a/static.getServletPath().getRequestURI()
Reid

3

できないと思います。他の唯一の構成の選択肢は、フィルタリングするパスを列挙することです。/*そのため/this/*、for /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

これにより、具体的なFilterクラスに嫌がらせをする必要がなくなります。


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.