Если вы используете домашнюю аутентификацию HTTP-запроса поверх JSF, тогда фильтр сервлетов - действительно лучший подход. JSF является «просто» инфраструктурой MVC, и в API JSF ничего не было указано для фильтрации входящих HTTP-запросов для проверки аутентификации пользователя. В обычных GET-запросах управляемый JSF-компонент обычно создается только тогда, когда HTTP-ответ собирается быть создан и отправлен или, возможно, уже зафиксирован. Это не контролируется изнутри управляемого компонента. Если ответ уже зафиксирован, вы больше не сможете его изменить (перенаправить). Аутентификация и изменение запроса / ответа действительно должны быть сделаны задолго до того, как ответ собирается быть отправленным.
Если бы вы не использовали аутентификацию homegrowing, вы могли бы использовать для этого управляемую контейнером аутентификацию Java EE, которая должна быть объявлена <security-constraint>
записями в web.xml
. Обратите внимание, что это также не связано с JSF, но, по крайней мере, избавляет вас от доморощенного создания фильтра сервлета и управляемого компонента.
Общий подход состоит в том, чтобы сгруппировать ограниченные страницы за определенным шаблоном URL, таким как /app/*
, /private/*
, /secured/*
и т. Д., И использовать тот факт, что JSF хранит bean-объекты области видимости в качестве атрибутов HttpSession
, Представьте, что у вас есть управляемый bean-компонент с областью действия JSF UserManager
, в котором содержится вошедший в систему пользователь, и вы можете проверить это следующим образом:
@WebFilter(urlPatterns={"/app/*"})
public class AuthenticationFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
UserManager userManager = (session != null) ? (UserManager) session.getAttribute("userManager") : null;
if (userManager == null || !userManager.isLoggedIn()) {
response.sendRedirect(request.getContextPath() + "/login.xhtml"); // No logged-in user found, so redirect to login page.
} else {
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
// ...
}
Если вы используете JSF 2.2+, есть другой способ контролировать ответ прямо перед его отправкой. Вы можете использовать <f:viewAction>
. Поместите следующее где-то на ваш взгляд:
<f:metadata>
<f:viewAction action="#{authenticator.check}" />
</f:metadata>
с
@Named
@RequestScoped // Scope doesn't matter actually. The listener will always be called on every request.
public class Authenticator {
public String check() {
if (authenticated) {
return null;
}
else {
return "login?faces-redirect=true";
}
}
// ...
}
Это гарантированно сработает до того, как ответ будет обработан. В противном случае, когда вы делаете работу, например, @PostConstruct
, тогда вы можете рискнуть java.lang.IllegalStateException: response already committed
, когда компонент создается в первый раз, когда ответ уже частично обработан (и зафиксирован).
Я бы не считал это "лучшей" практикой, когда дело касается обработки HTTP-аутентификации. Это делает его слишком тесно связанным с JSF. Вы действительно должны использовать фильтр сервлетов. Но для других целей это может быть хорошо.
Смотри также: