I have the following configuration in Spring Security:
http.requestMatchers().antMatchers("/admin/**", "/login", "/logout").and()
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.and().formLogin().loginPage("/main.xhtml")
.loginProcessingUrl("/login").defaultSuccessUrl("/admin.xhtml").and()
.exceptionHandling().accessDeniedPage("/denied.xhtml");
In a login controller (JSF backing bean) I have:
public void doLogin() throws ServletException, IOException {
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest)context.getRequest()).getRequestDispatcher("/login");
dispatcher.forward((ServletRequest)context.getRequest(), (ServletResponse)context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
}
I am using Primefaces for frontend components.
This is the login form:
<h:form id="form" prependId="false">
<p:messages id="errorMessages" showDetail="false" autoUpdate="true" />
<p:outputLabel for="username" value="Username" />
<p:inputText id="username" required="true" label="username" />
<p:outputLabel for="password" value="Password" />
<p:inputText id="password" required="true" label="password" />
<p:commandButton id="login" value="Login" update="errorMessages"
action="#{loginController.doLogin}" />
</h:form>
The problem is that the previous configuration forwards completely the response from Spring Security when trying to log in, so the login doesn't work. For it to work I would need to add ajax="false" in the p:commandButton but this would cause the whole page to reload in case of a login failure. Reloading the whole page breaks the user experience, for example, in my case users would need to scroll down to the login form if there's a login error.
How can I configure in either JSF or Spring Security so that I can do an AJAX login? Also, in this process, how could I show authentication failure messages from Spring Security?