Friday, April 22, 2011

JSF 2 Session Management

This article explains how you could manage sessions in JSF. The scenario we are going to look at is a blogging site which has restricted sections to non-logged-in users. If a non-logged-in user visits a page with access restrictions he/she would be redirected or taken to the login page. Only the logged users would have access to those pages.

What you could do is create a JSF Project at least with the following libraries

jsf-api.jar
jsf-impl.jar
jstl-api-1.2.jar
jstl-impl-1.2.jar

Note: Am using JSF 2 libraries.

For session management, you need to create a bean with a Session Scope. In our case we can create a bean called LoginBean. UserBean will have an EventListener called verifyIfUserLoggedIn. This is event will be attached to any pages which you would to restrict access using <f:event > tag.(To avoid adding the <f:event /> tag to all the pages you want to restrict access, you can include it in the template). Below is the code

LoginBean.java
import java.io.IOException;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;

@ManagedBean
@SessionScoped
public class LoginBean implements Serializable {
 private static final long serialVersionUID = 1L;
 private String username;
 private String password;
 private boolean isLoggedIn;

 public String login(){
  //custom member manager class
  MemberManager memberManager=new MemberManager();
  //default url in case of login failure;
  String url="login.jsf";

  //user a custom method to authenticate a user
  if(memberManager.authenticate(username, password)){
   //changed the state to true
   isLoggedIn=true;
   url="forum.jsf";
  }else{
   //set the message to display when authentication fails
   FacesContext.getCurrentInstance().addMessage("frmLogin:btnLogin", new FacesMessage("Invalid Username and or Password"));
  }
  return url;
 }

 /**
 * An event listener for redirecting the user to login page if he/she is not currently logged in
 * @param event
 */
 public void verifyUseLogin(ComponentSystemEvent event){
  if(!isLoggedIn){
   doRedirect("login.jsf");
  }
 }

 /**
 * Method for redirecting a request
 * @param url
 */
 private void doRedirect(String url){
  try {
   FacesContext context=FacesContext.getCurrentInstance();
   context.getExternalContext().redirect("login.jsf");
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

 public String getUsername() {
  return username;
 }
 public void setUsername(String username) {
  this.username = username;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 public boolean isLoggedIn() {
  return isLoggedIn;
 }
 public void setLoggedIn(boolean isLoggedIn) {
  this.isLoggedIn = isLoggedIn;
 }
}

Login Form
Login page will have a structure the following code
<h:form id="frmLogin">
 <h:message for="btnLogin" />
 <h:panelgrid columns="2">
  <h:outputtext value="Username" /><h:inputtext value="#{loginBean.username}" style="width: 106px;" />
  <h:outputtext value="Password" /><h:inputsecret value="#{loginBean.password}" style="width: 108px;" />
  <h:outputtext value="" /><h:commandbutton action="#{loginBean.login}" value="Login" id="btnLogin" />
 </h:panelgrid>
</h:form>

Attach Event Listener
Attach event listener to the page or view you want to restrict access as shown below (preferably in the head section).
<f:metadata>
 <f:event listener="#{loginBean.verifyUseLogin}" type="preRenderView">
</f:event>

I hope this article will be of help. Regards