Добавить сообщение JSF из Spring Bean

У меня проблема с добавлением сообщения в FacesContext из компонента Spring. Вот сенарио:

  1. Вход пользователей со страницы .xhtml
  2. Spring Security авторизует пользователя
  3. Если пользователь успешно/неуспешно, верните сообщение пользовательскому интерфейсу из управляемого класса Spring (AuthenticationFailureHandler, AuthenticationSuccessHandler), который является простым лицом.

Я не могу добавить сообщение через:

@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {

    private static Logger logger = LoggerFactory.getLogger(LoginFailureHandler.class);

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        logger.info("Login failed: " + httpServletRequest.getParameter("j_username"), e);
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Login Error", e.getLocalizedMessage());
        FacesContext.getCurrentInstance().addMessage(null, message);
        httpServletResponse.sendRedirect("/timsgui/login.jsf?error=1");
    }
}

Поскольку этот класс не находится в жизненном цикле JSF, FacesContext.getCurrentInstance() возвращает null. Вот моя jsf-страница:

<body>

    <p:growl id="growl" sticky="true" showDetail="true" life="3000" />

    <h:form name="login" action="../j_spring_security_check" method="POST">
        <h:panelGrid>
            <h:outputLabel for="j_username" value="Username:"/>
            <p:inputText id="j_username"/>

            <h:outputLabel for="j_password" value="Password:"/>
            <p:password id="j_password"/>

            <!-- need CSRF protection which is enabled default after Spring 4-->
            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
            <p:commandButton value="Login" update="growl" type="submit"/>
        </h:panelGrid>
    </h:form>

Я попытался внедрить FacesContext в бин Spring, но он все равно возвращает null:

@ManagedProperty("#{facesContext}")

Могу ли я в любом случае внедрить текущий FacesContext в Spring bean или какие-либо другие идеи, которые я могу добавить это глобальное сообщение из Spring Bean в FacesContext без FacesContext.getCurrentInstance().addMessage()?


person cmlonder    schedule 23.08.2017    source источник
comment
FacesContext нет, так как вы работаете вне сервлета JSF. То, чего нет, недоступно. Также @ManagedProperty в bean-компоненте Spring ничего не сделает, поскольку @ManagedProperty должен использоваться в управляемых bean-компонентах JSF, а не в управляемых bean-компонентах Spring.   -  person M. Deinum    schedule 23.08.2017
comment
Я знаю: поскольку этот класс не находится в жизненном цикле JSF, FacesContext.getCurrentInstance() возвращает значение null. Чем можно вернуть сообщение из Spring Security в сервлет JSF?   -  person cmlonder    schedule 23.08.2017
comment
Найдите какое-нибудь промежуточное решение. Сохраните их в объявлении сеанса перед рендерингом страницы, установите их как сообщения лиц (или что-то подобное).   -  person M. Deinum    schedule 23.08.2017
comment
Даже если вы используете JSF для своего приложения, эта форма полностью избавляет от жизненного цикла JSF. Вы в основном выполняете POST против конечной точки, отличной от JSF. Итак, как говорит Дейнум, вы можете написать какой-нибудь хак, например, с использованием области сеанса. Другой альтернативой может быть отказ от использования простых лиц на странице входа и использование javascript для отображения сообщения из ответа.   -  person Xtreme Biker    schedule 23.08.2017
comment
Просто используйте способ Spring, чтобы добавить сообщение.   -  person BalusC    schedule 23.08.2017


Ответы (1)


Хорошо, я решил это. Спасибо @M.Delinum и @Xtreme Biker за ваши предложения. Я ввел сообщение в HttpSession и получил его из области http. Вот окончательный код:

@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {

    private static Logger logger = LoggerFactory.getLogger(LoginFailureHandler.class);

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        logger.info("Login failed: " + httpServletRequest.getParameter("j_username"), e);
        HttpSession session = httpServletRequest.getSession(false);
        if (session != null) {
            session.setAttribute("loginFailMessage", "Login is failed");
        }
        httpServletResponse.sendRedirect("/timsgui/login.jsf?error=true");
    }
}
<h:outputText value="#{sessionScope['loginFailMessage']}" rendered="#{not empty sessionScope['loginFailMessage']}" styleClass="highlight"/>
person cmlonder    schedule 23.08.2017