I have a JSF 2.2 application with PrimeFaces 5.2 and form-based login in combination with a JBoss security realm using Wildfly 8.2 and PostgreSQL.
This is working fine and absolutely as expected. The problem now is using the above setup with PrimeFaces Mobile. After having entered username and password and clicking the login button nothing happens as I get redirected to the login view again insted of either a redirect to the original requested page or the error page.
Let's start with my mobile login form:
<ui:define name="content">
<pm:content styleClass="content">
<h:form id="loginForm" method="POST" prependId="false"
onsubmit="document.getElementById('loginForm').action = 'j_security_check';">
<p:focus for="j_username"/>
<pm:field>
<p:outputLabel value="Benutzername"></p:outputLabel>
<h:inputText id="j_username" name="j_username" required="true" />
</pm:field>
<pm:field>
<p:outputLabel value="Passwort"></p:outputLabel>
<p:password id="j_password" name="j_password" redisplay="false" required="true" />
</pm:field>
<pm:field>
<p:commandButton id="login" value="Login" ajax="false" />
</pm:field>
</h:form>
</pm:content>
</ui:define>
As mentioned earlier the form definition works with the non-mobile version, for the mobile version I just added tags pm_content
and pm:field
.
When inspecting the generated DOM in Chrome I can see that the rendered mobile version of the page has different ids for the form and input elements than the non-mobile version and also the onsubmit
is missing:
<form id="j_idt6:loginForm" name="j_idt6:loginForm" method="post" action="/MyApp/login.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_idt6:loginForm" value="j_idt6:loginForm">
<span id="j_idt6:j_idt32"></span><script type="text/javascript">$(function(){PrimeFaces.focus('j_idt6:username');});</script><div class="ui-field-contain"><label id="j_idt6:j_idt16" class="ui-outputlabel ui-widget">Benutzername</label><div class="ui-input-text ui-body-inherit ui-corner-all ui-shadow-inset"><input id="j_idt6:username" type="text" name="j_idt6:username"></div></div><div class="ui-field-contain"><label id="j_idt6:j_idt18" class="ui-outputlabel ui-widget">Passwort</label><div id="j_idt6:password" class="ui-input-text ui-body-inherit ui-corner-all ui-shadow-inset ui-input-has-clear"><input data-role="none" id="j_idt6:password" name="j_idt6:password" type="password"><a href="#" class="ui-input-clear ui-btn ui-icon-delete ui-btn-icon-notext ui-corner-all ui-input-clear-hidden"></a></div></div><div class="ui-field-contain"><button id="j_idt6:login" name="j_idt6:login" class="ui-btn ui-shadow ui-corner-all" onclick="" type="submit">Login</button></div><input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="-5673897088131963149:-3654042330506594383" autocomplete="off">
</form>
Now the generated output from the non-mobile login:
<form id="loginForm" name="loginForm" method="post" action="/MyApp/login.xhtml" enctype="application/x-www-form-urlencoded" onsubmit="document.getElementById('loginForm').action = 'j_security_check';">
<input type="hidden" name="loginForm" value="loginForm">
<span id="j_idt11"></span><script type="text/javascript">$(function(){PrimeFaces.focus('j_username');});</script><input id="j_username" type="text" name="j_username"><input id="j_password" type="password" name="j_password" value=""><input id="login" type="submit" name="login" value="Login"><input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="5464337132357101375:3961658655950415709" autocomplete="off">
</form>
If I get it right there seems to be a problem with prepending the ids in the mobile version.
How can I fix this and implement a POST to j_security_check
in PrimeFaces Mobile 5.2?
I was able to tinker a working solution with the hint of @BalusC so that my form now looks like this:
<ui:define name="content">
<pm:content styleClass="content">
<h:form>
<pm:field>
<h:outputLabel for="username" value="Username" />
<h:inputText id="username" value="#{authenticationBean.username}"
required="true" />
<h:message for="username" />
</pm:field>
<pm:field>
<h:outputLabel for="password" value="Password" />
<h:inputSecret id="password" value="#{authenticationBean.password}"
required="true" />
<h:message for="password" />
</pm:field>
<pm:field>
<h:commandButton value="Login" action="#{authenticationBean.login()}" />
</pm:field>
</h:form>
</pm:content>
</ui:define>
The login is now programmatic inside the @ViewScoped
managed bean AuthenticationBean within the login method:
public void login() {
log.info("Login attempt");
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
try {
request.login(username, password);
log.info("Login successful");
externalContext.redirect(originalURL);
} catch (ServletException e) {
// Handle unknown username/password in request.login().
context.addMessage(null, new FacesMessage("Unknown login"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}