Я склонен использовать <f:event>
в preRenderView, который будет обновлять компонент сообщений в моей форме.Вот как я это сделал.
<f:event listener="#{loginBean.updateMessages(true)}" type="preRenderView" />
<div style="margin-left: 50px; width: 500px;"><br />
<h:form id="loginForm" prependId="false">
<p:messages id="errorMessages" />
<label for="j_username">
<h:outputText value="Username:" /><br />
</label>
<h:inputText id="j_username" required="true" width="500" style="width: 300px;" />
<br />
<br />
<label for="j_password">
<h:outputText value="Password:" /><br />
</label>
<h:inputSecret id="j_password" required="true" width="500" style="width: 300px;" />
<h:link value="Forgot my password" outcome="forgotpassword" />
<br />
<br />
<label for="_spring_security_remember_me">
<h:outputText value="Remember me" />
</label>
<h:selectBooleanCheckbox id="_spring_security_remember_me" />
<br /><br />
<p:commandButton ajax="false" type="submit" id="login" action="#{loginBean.doLogin}" value="Login" update="errorMessages" />
</h:form>
</div>
И затем в моем управляемом компоненте LoginBean я перенаправляю запрос на сервлет Spring Security и обновляю сообщения.Вы заметите, что у меня также есть код для действия по выходу из системы, если вам интересно узнать, как я подошел к этой проблеме.
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username.trim();
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password.trim();
}
public void updateMessages(boolean update) throws Exception {
System.out.println("Start LoginBean.updateMessages");
ex = (Exception)FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.get(WebAttributes.AUTHENTICATION_EXCEPTION);
if (ex != null) {
log.error("Authentication Failed! ", ex);
System.err.println("Authentication Failed! " + ex.getMessage());
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), ex.getMessage()));
}
System.out.println("End LoginBean.updateMessages");
}
public String doLogin() {
log.info("Start LoginBean.doLogin");
try {
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
.getRequestDispatcher("/j_spring_security_check");
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
// It's OK to return null here because Faces is just going to exit.
} catch (Exception e) {
log.error("Exception doLogin", e);
} finally {
log.info("End LoginBean.doLogin");
}
return "";
}
public String logout() {
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
if (!sessionMap.containsKey("sessionBean"))
return "";
SessionBean sessionBean = (SessionBean)sessionMap.get("sessionBean");
log.info("Logging out user: " + sessionBean.getLoggedInUser().getUsername());
sessionMap.remove("sessionBean");
//HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
//session.invalidate();
RequestDispatcher dispatcher = ((ServletRequest) context.getExternalContext().getRequest())
.getRequestDispatcher("/j_spring_security_logout");
try {
dispatcher.forward((ServletRequest) context.getExternalContext().getRequest(),
(ServletResponse) context.getExternalContext().getResponse());
} catch (ServletException e) {
log.error("ServletException", e);
} catch (IOException e) {
log.error("IOException", e);
}
FacesContext.getCurrentInstance().responseComplete();
// It's OK to return null here because Faces is just going to exit.
log.info("End LoginBean.logout");
return "";
}
public boolean isLoggedIn() {
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
return sessionMap.containsKey("sessionBean");
}
РЕДАКТИРОВАТЬ:
Iдумаю, я лучше понимаю вашу проблему сейчас.Я помню, что у меня были проблемы с тем, чтобы заставить это работать, поэтому в основном мне пришлось написать свой собственный класс, который реализует AuthenticationFailureHandler
и правильно реализовать метод:
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, ServletException {
//Do business logic stuff, logging, etc...
request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, ex);
response.sendRedirect("login.xhtml");
В основном вы видите, что я создаю исключениеи установив его в качестве атрибута сеанса, чтобы позже в моем управляемом компоненте его можно было извлечь и преобразовать в FacesMessage
.
. Вам также придется объявить этот AuthenticationFailureHandler
как пользовательский обработчик для событий сбоя аутентификации.в вашем файле конфигурации Spring Security (обратите внимание, что я также показываю, что я делаю то же самое для обработчика успешной аутентификации, но вы можете или не хотите делать это также) .
<form-login login-page="/login.xhtml" login-processing-url="/j_spring_security_check"
authentication-success-handler-ref="authenticationSuccessBean"
authentication-failure-handler-ref="authenticationFailureBean" />
...
<beans:bean id="authenticationFailureBean" class="com.maple.controllers.FailureHandler">
<beans:property name="userBo" ref="userController" /> <!-- Just injecting my BL layer... -->
</beans:bean>