ユーザーが一部のページのURLを知っていても、一部のページへのアクセスをブロックしたいと思います。たとえば、/localhost:8080/user/home.xhtml
(最初にログインする必要があります)ログに記録されていない場合は、/index.xhtml
にリダイレクトします。
JSFでそれを行う方法は?フィルターが必要なGoogleの記事を読みましたが、その方法はわかりません。
_javax.servlet.Filter
_ クラスを実装し、doFilter()
メソッドで目的のジョブを実行し、制限されたページをカバーするURLパターンにマップする必要があります。_/user/*
_ ? doFilter()
内では、セッション内のログインユーザーの存在を何らかの方法で確認する必要があります。さらに、JSF ajaxおよびリソースリクエストも考慮する必要があります。 JSF ajaxリクエストには、JavaScriptがリダイレクトを実行できるようにするための特別なXML応答が必要です。 JSFリソースリクエストはスキップする必要があります。そうしないと、ログインページにCSS/JS /イメージがなくなります。
externalContext.getSessionMap().put("user", user)
経由でJSFマネージドBeanにログインしたユーザーを保存する_/login.xhtml
_ページがあると仮定すると、session.getAttribute("user")
経由で取得できます以下:
_@WebFilter("/user/*")
public class AuthorizationFilter implements Filter {
private static final String AJAX_REDIRECT_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<partial-response><redirect url=\"%s\"></redirect></partial-response>";
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURL = request.getContextPath() + "/login.xhtml";
boolean loggedIn = (session != null) && (session.getAttribute("user") != null);
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER + "/");
boolean ajaxRequest = "partial/ajax".equals(request.getHeader("Faces-Request"));
if (loggedIn || loginRequest || resourceRequest) {
if (!resourceRequest) { // Prevent browser from caching restricted resources. See also https://stackoverflow.com/q/4194207/157882
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response); // So, just continue request.
}
else if (ajaxRequest) {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().printf(AJAX_REDIRECT_XML, loginURL); // So, return special XML response instructing JSF ajax to send a redirect.
}
else {
response.sendRedirect(loginURL); // So, just perform standard synchronous redirect.
}
}
// You need to override init() and destroy() as well, but they can be kept empty.
}
_
さらに、フィルターはセキュリティで保護されたページのブラウザーキャッシュも無効にするため、ブラウザーの[戻る]ボタンはそれらを表示しなくなります。
JSFユーティリティライブラリ OmniFaces を使用する場合、上記のコードは以下のように削減できます。
_@WebFilter("/user/*")
public class AuthorizationFilter extends HttpFilter {
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, HttpSession session, FilterChain chain) throws ServletException, IOException {
String loginURL = request.getContextPath() + "/login.xhtml";
boolean loggedIn = (session != null) && (session.getAttribute("user") != null);
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = Servlets.isFacesResourceRequest(request);
if (loggedIn || loginRequest || resourceRequest) {
if (!resourceRequest) { // Prevent browser from caching restricted resources. See also https://stackoverflow.com/q/4194207/157882
Servlets.setNoCacheHeaders(response);
}
chain.doFilter(request, response); // So, just continue request.
}
else {
Servlets.facesRedirect(request, response, loginURL);
}
}
}
_
もちろん、単純なサーブレットフィルターを使用することは正当ですが、次のような代替手段もあります。