Saturday, 11 February 2012

Struts2 Login Interceptor



Recently I spent up a whole day searching for solutions to build up a Login Interceptor. It took almost about 8 hours because I had to piece together the information that I needed from multiple locations and then I had to experiment and test the solutions in my application.

Hence, I am taking what I have learned and represnting it here so that others may not have to waster a similar amount of time searching for this topic.

This is the design of the project in Netbeans:


1. web.xml (needs no change)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <filter>        
<filter-name>struts2</filter-name>
        <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class>
    </filter>    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>
        <session-timeout>             30         </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>


2. admin.jsp
<h1>Hello Admin!</h1>

3.index.jsp
        <s:if test="#session['login']!=null">
            <!--<s:property value="#session['login']"/>-->
            <s:url id="logout" action="logoutaction"/>
            <s:a href="%{logout}">Logout</s:a>
        </s:if>
        <s:else>
            <s:a href="login.jsp">Login</s:a>
        </s:else>

        Welcome <s:property value="msg" default="Guest"/>

        <s:url id="admin1" action="admin1action"/>
        <s:url id="admin2" action="admin2action"/>
        <s:a href="%{admin1}">Admin Action One</s:a>
        <s:a href="%{admin2}">Admin Action Two</s:a>

4. login.jsp
        <s:if test="#request['errorMsg']!=null">
            <s:property value="#request['errorMsg']"/>
        </s:if>
        <s:actionerror/>
        <s:form action="loginaction" method="post">
            <s:textfield name="username" label="Username" />
            <s:password name="password" label="Password"/>
            <s:submit value="submit"/>
        </s:form>

5. MyInterceptor.java
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.interceptor.Interceptor;
import java.util.Map;

public class MyInterceptor implements Interceptor {

    public void destroy() {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void init() {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    public String intercept(ActionInvocation ai) throws Exception {
        Map sess = ai.getInvocationContext().getContext().getSession();
        if (sess.containsKey("login")) {
            return ai.invoke();
        }
        Object action = ai.getAction();
        if (action instanceof ValidationAware) {
            ((ValidationAware) action).addActionError("Unauthorized access. Please Login first");
        }
        return "login";
    }
}

6. struts.xml
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <!-- Configuration for the default package. -->
    <package name="default" extends="struts-default" namespace="">
        <interceptors>
            <interceptor name="nlogin" class="MyInterceptor"/>
            <interceptor-stack name="loginStack">
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="nlogin"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation"/>
                <interceptor-ref name="workflow"/>
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="loginStack"/>
       
        <global-results>
            <result name="login">/login.jsp</result>
        </global-results>
       
       
        <action name="admin1action" class="actions.AdminActionOne">
            <result name="success">index.jsp</result>
        </action>
        <action name="admin2action" class="actions.AdminActionTwo">
            <result name="success">index.jsp</result>
        </action>
       
        <action name="loginaction" class="actions.MyAction">
            <interceptor-ref name="defaultStack"/>
            <result name="success">index.jsp</result>
            <result name="input">login.jsp</result>
        </action>

        <action name="logoutaction" class="actions.MyAction" method="logout">
            <interceptor-ref name="defaultStack"/>
            <result name="success">index.jsp</result>
        </action>
    </package>
</struts>

7. AdminActionOne.java
package actions;

import com.opensymphony.xwork2.ActionSupport;
public class AdminActionOne extends ActionSupport
{
    private String msg;
    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String execute(){
        msg="Admin One";
        return SUCCESS;
    }
}

8. AdminActionTwo.java
package actions;
import com.opensymphony.xwork2.ActionSupport;
public class AdminActionTwo extends ActionSupport {
    private String msg;
    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String execute() {
        msg="Admin Two";
        return SUCCESS;
    }
}

9. MyAction.java
package actions;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
public class MyAction extends ActionSupport
{
    private String username;
    private String password;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    private String errorMsg;

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public String execute(){
        if(username.equalsIgnoreCase(password)){
            Map sess=ActionContext.getContext().getSession();
            sess.put("login", true);
            return SUCCESS;
        }
        errorMsg="Invalid username/password";
        return INPUT;
    }

    public String logout(){
        Map sess=ActionContext.getContext().getSession();
        sess.remove("login");
        return SUCCESS;
    }

}



That's all. I guess now you must have figured out what to write and where to write and even how to write.
Let me know your problems in case this solution doesn't work in your context.

1 comment:

  1. Thanks for the tutorial. Please change the font color of the code from Aqua to some readable color.

    ReplyDelete