Ответ 1
Я смог воспроизвести вашу проблему. Что здесь происходит, так это то, что контейнер вызывает RequestDispatcher#forward()
на странице входа, как указано в ограничении безопасности. Однако, если страница входа сама по себе является страницей JSF, тогда также будет вызываться FacesServlet
по пересылаемому запросу. Поскольку запрос является переадресацией, это просто создаст новое представление для перенаправленного ресурса (страница входа). Однако, поскольку это ajax-запрос и там нет render
информации (весь запрос POST в основном отбрасывается во время проверки безопасности вперед), возвращается только состояние представления.
Обратите внимание, что если страница входа в систему не была страницей JSF (например, JSP или простой HTML), тогда запрос ajax вернул бы весь вывод HTML страницы как ajax-ответ, который не поддается JSF ajax и интерпретируется как "пустой" ответ.
Это, к сожалению, работает "как запроектировано". Я подозреваю, что существует некоторый надзор в спецификации JSF для проверки ограничений безопасности на запросы ajax. Причина в конце концов понятна и, к счастью, легко решить. Только, вы действительно не хотите показывать страницу с ошибкой здесь, а вместо этого просто страницу входа полностью, точно так же, как это произошло во время запроса без аякса. Вам просто нужно проверить, является ли текущий запрос ajax-запросом и был отправлен на страницу входа в систему, тогда вам нужно отправить специальный ответ "перенаправление" ajax, чтобы весь вид был изменен.
Вы можете достичь этого с помощью PhaseListener
следующим образом:
public class AjaxLoginListener implements PhaseListener {
@Override
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
@Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
@Override
public void afterPhase(PhaseEvent event) {
FacesContext context = event.getFacesContext();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
String originalURL = (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
String loginURL = request.getContextPath() + "/login.xhtml";
if (context.getPartialViewContext().isAjaxRequest()
&& originalURL != null
&& loginURL.equals(request.getRequestURI()))
{
try {
context.getExternalContext().invalidateSession();
context.getExternalContext().redirect(originalURL);
} catch (IOException e) {
throw new FacesException(e);
}
}
}
}
Обновить это решение с тех пор, как OmniFaces 1.2 был встроен в OmniPartialViewContext
. Поэтому, если вы уже используете OmniFaces, эта проблема будет полностью прозрачно решена, и для этого вам не нужен пользовательский PhaseListener
.