Your filter looks fine (apart from the very weak url.contains("login")
test and the in 2 ways incorrect attempt to set the response status to 301 and the a bit poor way of checking a logged-in user).
I think that your concrete problem is caused that you're performing navigaiton by ajax links instead of normal links. You can't send a redirect on an ajax response this way. Neither the JSF ajax engine nor the webbrowser follows 302 redirects on JSF ajax responses. The client ends up with an ajax response which is totally ignored.
Instead, you should be sending a special XML response which instructs the JSF ajax engine to send a redirect. It's exactly that XML response as is been sent when inside the JSF context the ExternalContext#redirect() is been used during an ajax request.
<?xml version="1.0" encoding="UTF-8"?>
<partial-response>
<redirect url="/contextpath/login/login.xhtml"></redirect>
</partial-response>
Inside the servlet filter, you should thus first check if the request concerns a JSF ajax request and if so, then return the above XML response, otherwise just invoke HttpServletResponse#sendRedirect()
the usual way. You can do that by checking if the Faces-Request
request header is present and equals to partial/ajax
.
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
// It's a JSF ajax request.
}
So, all with all, your doFilter()
should look now like this:
String loginURL = req.getContextPath() + "/login/login.xhtml";
if (!authenticated && !req.getRequestURI().equals(loginURL)) {
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
res.setContentType("text/xml");
res.getWriter()
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", loginURL);
} else {
res.sendRedirect(loginURL);
}
} else {
chain.doFilter(request, response);
}