k_rollo
k_rollo

Reputation: 5472

Using Interceptor to validate user access privilege

I am trying to use an Interceptor to restrict users from performing certain actions.

ContainsKeyInterceptor:

public class ContainsKeyInterceptor extends AbstractInterceptor implements SessionAware {
    private static final long serialVersionUID = 1L;

    private Map<String, Object> session;

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        if(session == null) {
            System.out.println("session is null");
        }

        if(session.containsKey("currentId")) {
            return "index";
        }

        String result = actionInvocation.invoke();

        return result;
    }

    @Override
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }
}

It is supposed to redirect the user to the index page if currentId is found in the session.

However, I am getting a NullPointerException, saying session is null, as verified by the if-check.

struts.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <constant name="struts.devMode" value="false" />

    <!-- actions available to guests -->
    <package name="guest" extends="struts-default">
        <interceptors>
            <interceptor name="containskeyinterceptor" class="com.mypackage.interceptor.ContainsKeyInterceptor" />
        </interceptors>

        <action name="index" class="com.mypackage.action.IndexAction">
            <interceptor-ref name="containskeyinterceptor" />
            <result type="redirect">/index.jsp</result>
            <result name="index" type="redirect">/index.jsp</result>
        </action>

        <action name="login" class="com.mypackage.action.LoginAction">
            <interceptor-ref name="containskeyinterceptor" />
            <result type="redirect">/index.jsp</result>
            <result name="input">/login.jsp</result>
            <result name="index" type="redirect">/index.jsp</result>
        </action>       
    </package>

    <!-- actions available to members -->
    <package name="member" extends="struts-default">
        <action name="logout" class="com.mypackage.action.LogoutAction">
            <result type="redirectAction">
                <param name="actionName">index</param>
            </result>
        </action>
    </package>
</struts>

Why is the session null and how to resolve?

(This was the reference I used.)

Upvotes: 1

Views: 1346

Answers (2)

Andrea Ligios
Andrea Ligios

Reputation: 50261

Struts Session is just a Map<String,Object> wrapping the underlying HttpSession.

While implementing the SessionAware interface is the correct way to get it in an Action, if you want to get it from within an Interceptor, you need to do the following:

To get the Struts Session Map:

@Override
public String intercept(ActionInvocation ai) throws Exception {
    final ActionContext context = ai.getInvocationContext();

    // Struts Session
    Map<String, Object> session = context.getSession();

To get the real HttpSession object:

@Override
public String intercept(ActionInvocation ai) throws Exception {
    final ActionContext context = ai.getInvocationContext();

    HttpServletRequest request = (HttpServletRequest)context.get(StrutsStatics.HTTP_REQUEST);

    // Http Session
    HttpSession session = request.getSession();

That said, the reason you are not getting session (nor any other parameter, object and so on) in your Actions, is because you are falling in a common mistake: applying only one Interceptor (your) instead of applying an entire Interceptor Stack (that should contain your):

You can define it twice in every action:

<action name="login" class="ph.edu.iacademy.action.LoginAction">
    <interceptor-ref name="defaultStack" /> <!-- this is missing -->
    <interceptor-ref name="containskeyinterceptor" />

or, much better, define it once in a custom stack, and use always the stack:

<interceptors>
    <interceptor-stack name="yourStack">                
       <interceptor-ref name="defaultStack"/>
       <interceptor-ref name="containskeyinterceptor"/>
    </interceptor-stack>
</interceptors>

<action name="login" class="ph.edu.iacademy.action.LoginAction">
    <interceptor-ref name="yourStack" />

and eventually define it with default-interceptor-ref to avoid writing it for every action config of that package:

<default-interceptor-ref name="yourStack"/>

<action name="login" class="ph.edu.iacademy.action.LoginAction">

Upvotes: 2

Joeblade
Joeblade

Reputation: 1743

Based on this I don't think the interceptor itself can / needs to be session aware.

You can access this property as such:

final ActionContext context = actionInvocation.getInvocationContext();  
this.session = context.getSession();  

There may be a way to get this set automatically, I'm not too familiar with struts2, but it could be that the sessionaware only works for a specific subset of objects and this interceptor isn't one of them for some reason. (not being scanned, being excluded from scan, of the wrong type)

Upvotes: 2

Related Questions