JSFのFaceletsでxhtmlに直接アクセスさせない方法

JSFでFaceletsを作成すると/facesでアクセスする場合は良いのですが、直接xhtmlファイルにアクセスするとソースがそのまま表示されて微妙な感じですよね。xhtmlファイルに直接アクセスさせないようにするには基本JSPで行う対処法と変わりません。


ただし、JSPでもっともよく使われているWEB-INF配下にファイルを配置する方法が、faceletsの場合テンプレートファイルでは可能ですが普通のファイルでは使えないと思うのでその他2つの方法を試してみたいと思います。

web.xmlのsecurity-constraintを使用する方法

特にアプリケーションの認証でsecurity-constraintを使用していない場合、security-constraintでxhtmlにアクセス制限を付加する事で直接アクセスを防ぐ事ができます。ただし、web.xmlのURLパターンマッチングは簡単なマッチングしか記載出来ないためパスがfacesで始まるかどうかをハンドリングできません。そのためFacesServletのURLパターンマッチングを.jsf等に変えてあげる必要があります。


servlet-mappingを変更

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>


security-constraintを設定

  <security-constraint>
    <display-name>XHTML Security</display-name>
    <web-resource-collection>
      <web-resource-name>Protected Area</web-resource-name>
      <url-pattern>*.xhtml</url-pattern>
    </web-resource-collection>
    <auth-constraint>
    </auth-constraint>
  </security-constraint>


このような設定を行うことで.jsfへのアクセスは許可し、.xthmlへのアクセスは拒否することができます。パターンマッチングを*.jsfに変える事でURLが変わってしまうのでその点は注意して使用する必要があります。

Filterを使う方法

ServletFilterを使用してxhtmlへのアクセスを制限します。ここでもurl-patternマッチングが貧弱なので*.xhtmlへのアクセスをフィルタで受けてそのパスが/facesで始まっているか確認します。


web.xml

    <filter>
        <filter-name>XHTMLSecurity Filter</filter-name>
        <filter-class>filter.XHTMLSecurityFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>XHTMLSecurity Filter</filter-name>
        <url-pattern>*.xhtml</url-pattern>
    </filter-mapping>


XHTMLSecurityFilter.java

package filter;

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;

public class XHTMLSecurityFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String path = ((HttpServletRequest) request).getServletPath();
        if (path.startsWith("/faces")) {
            chain.doFilter(request, response);
        } else {
            ((HttpServletResponse) response).sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    @Override
    public void destroy() {
    }
    
}


これでxhtmlファイルが表示されてしまう問題が解消できます。

結論

web.xmlのURLパターンマッチングをどうにかしてほしい。