Struts2 handle session timeout using Interceptor

2019-06-06 03:38发布

I am trying to handle session timeout requests in my struts2 application using an Interceptor. Below are the files related to this:

Web.xml:

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
    <session-timeout>1</session-timeout>
</session-config>

Struts.xml:

<package name="default" extends="struts-default">
<interceptors>
    <interceptor name="sessionInterceptor"
        class="com.platform.web.security.SessionInterceptor" />
</interceptors>
<action name="doLogin"
    class="com.platform.web.action.LoginAction">
    <result name="input">/login/login.jsp</result>
    <result name="error">/login/login.jsp</result>
    <result type="chain">menuAction</result>
</action>

<action name="menuAction"
    class="com.platform.web.action.MenuAction">
    <interceptor-ref name="sessionInterceptor"/> //Interceptor included here
    <result name="SUCCESS">/jsp/main.jsp</result>
    <result name="ERROR">/login/login.jsp</result>
    <result name="input">/jsp/myFavourite.jsp</result>
</action>

Interceptor Class:

public class SessionInterceptor extends AbstractInterceptor implements StrutsStatics {
/**
 * 
 */
private static final long serialVersionUID = 1L;

@Override
public String intercept(ActionInvocation invocation) throws Exception {

final ActionContext context = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context
    .get(HTTP_REQUEST);
HttpSession session = request.getSession(false);

// Is there a "user" object stored in the user's HttpSession?
//Object user = session.getAttribute("User");
if (session == null) {
    // The user has not logged in yet.

    // Is the user attempting to log in right now?
    //String loginAttempt = request.getParameter(LOGIN_ATTEMPT);

    /* The user is attempting to log in. */
    /*if (!StringUtils.isBlank(loginAttempt)) {
    return invocation.invoke();
    }*/
    return "timeout";
 } else {
    return invocation.invoke();
 }
 }
}

LoginAction:

public class LoginAction extends MesActionSupport implements ServletRequestAware {
@Override
public String execute() throws Exception {
setActionNameForAudit("execute123");
FILE_LOGGER.debug("Entering into execute() ... ");
String strSessionId = "";

if (isValidUser == true) {
    user = getUser();

    strSessionId = request.getSession(true).getId();
    setServletRequest(request);
    session.put("SessionId", strSessionId);

    setSession(session, user);

    ServletActionContext.getRequest().getSession().setAttribute("User", user);

    FILE_LOGGER.debug("Exit from  LoginAction.execute() ... ");
    return SUCCESS;
} else {
    return ERROR;
}
 }

MenuAction:

public class MenuAction extends MesActionSupport implements SessionAware, ParameterAware, RequestAware {
@Override
public String execute() throws Exception {
setActionNameForAudit("execute ");
User user = null; // To store current user
Map<String, ArrayList<String>> category = null; // To store all Menu
// Categories.
StringBuffer menu = new StringBuffer(""); // To store Menu String
StringBuffer dashboardMenu = new StringBuffer("");

// user = (User)(request.getSession().getAttribute("User")==null ? null : request.getSession().getAttribute("User")); //Request object IS NULL HERE!!
user = (User) (mapSession.get("User") == null ? null : mapSession
    .get("User")); // mapSession object IS NULL HERE
FILE_LOGGER.debug("user is " + user == null);

if (user != null) {
    menu = menuView.getMenu(user);
    mapSession.put("Menu", menu.toString());
    mapSession.put("dbMenu", dashboardMenu.toString());
    ret = "SUCCESS";
} else if (user == null) {
    ret = ERROR;
} else {
    ret = SUCCESS;
}
return ret;
}

Flow is like this: 1. Login screen opens 2. User enters credentials and submits 3. LoginAction is called, user is authenticated 4. If valid user - MenuAction is called. Else redirect to Login.jsp

According to the above code, the session gets created in the LoginAction, control reaches the Interceptor where the session object is checked. If session exists the control reaches MenuAction.

But when this happens, the request object gets reset to NULL! Earlier when I was not using an interceptor, the flow was working completely fine between LoginAction and MenuAction.

Does the interceptor resets the HTTPRequest? and hence the Session? As a result I am not able to proceed.

Any help?

2条回答
干净又极端
2楼-- · 2019-06-06 03:48

I have many comments on this code/configuration, some trivial, some not.

  1. There's zero reason to create your own session; don't.

  2. When you declare an interceptor in an action configuration you must declare all interceptors. As configured, only the session interceptor is running for menuAction.

  3. That means no parameters will be filled, since no other interceptors are running.

  4. In general, only use SessionAware to access the session. There is very rarely a need to access the request directly.

  5. Obviously the interceptor doesn't "set the request to null", that doesn't even make sense.

  6. I have no idea what your LoginAction is supposed to be doing. What's the intent of lines like setServletRequest(request); or setSession(session, user);? There's nothing about those two lines that look correct.

  7. Name your success and error results just that, "success" and "error" (lower case), if you're going to use the ActionSupport.SUCCESS and ActionSupport.ERROR constants. If you're not using those constants in this code, I'd recommend using other names for them, because it will confuse anybody that has actually used Struts 2 before.

  8. When posting code samples please remove stuff that isn't relevant. Particularly when you don't explicitly set syntax highlighting it makes things much more difficult to read.

  9. Don't use code like if (isValidUser == true), use if (isValidUser).

  10. Mind your conditionals: stuff like if (user == null) ... else if (user != null) ... else ... makes zero sense. The user is null, or it isn't: there's no third option.

  11. Avoid unnecessary, confusing logic, like User currentUser = (User) (mapSession.get("User") == null ? null : mapSession.get("User")); which basically says "If it's null, use null, otherwise return the value you just got, but get it again." WHY???

  12. Comments like User user = null; // To store current user are completely worthless. Isn't it obvious what User user is? A user. Not obvious enough? How about User currentUser???

  13. Name plurals (e.g., collections) as something plural. A map of category names to lists isn't a single category.

  14. Don't declare variables far away from where they're used; it's very confusing.

  15. Put your JSP pages under WEB-INF somewhere to disallow direct client access.

  16. Avoid unnecessary language constructs, like when an if branch returns, an else isn't strictly necessary, and IMO, it adds noise. Similarly, consider returning as soon as you know you're returning. The latter is a bit more controversial, but I think people are coming around to realizing it's okay to have multiple return points in short methods, and IMO it's easier to think about.

  17. Use less code to say things. Create little utility methods to wrap up trivial functionality so it doesn't pollute the mainline code.

  18. Use action chaining almost never.

There's more, but that's enough for now. Here's the actual relevant code, cleaned up. Some of it isn't actually relevant but I left it in anyway.


<filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

<session-config>
  <session-timeout>1</session-timeout>
</session-config>
<package name="default" extends="struts-default">
  <interceptors>
    <interceptor name="sessionInterceptor" class="com.platform.web.security.SessionInterceptor" />
  </interceptors>

  <action name="doLogin" class="com.platform.web.action.LoginAction">
    <result name="input">/WEB-INF/jsp/login/login.jsp</result>
    <result name="error">/WEB-INF/jsp/login/login.jsp</result>
    <result type="redirectAction">menuAction</result>
  </action>

  <action name="menuAction" class="com.platform.web.action.MenuAction">
    <interceptor-ref name="sessionInterceptor"/>
    <result name="success">/WEB-INF/jsp/main.jsp</result>
    <result name="input">/WEB-INF/jsp/myFavourite.jsp</result>
  </action>
 public class SessionInterceptor extends AbstractInterceptor implements StrutsStatics {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        ActionContext context = invocation.getInvocationContext();
        HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
        HttpSession session = request.getSession(false);

        // session will almost *never* be null. Check for a valid user object.
        if (session == null) {
            return "timeout";
        }

        return invocation.invoke();
    }
}
public class LoginAction extends MesActionSupport implements ServletRequestAware {
    @Override
    public String execute() throws Exception {
        if (!isValidUser) {
            return ERROR;
        }

        user = getUser();

        String strSessionId = request.getSession(true).getId();
        setServletRequest(request);
        session.put("SessionId", strSessionId);

        setSession(session, user);

        ServletActionContext.getRequest().getSession().setAttribute("User", user);

        return SUCCESS;
    }
}
public class MenuAction extends MesActionSupport implements SessionAware, ParameterAware, RequestAware {
    @Override
    public String execute() throws Exception {
        User currentUser = (User) mapSession.get("User");
        if (currentUser == null) {
            return ERROR;
        }

        Map<String, List<String>> categories; // Left in for naming.

        StringBuffer menu = menuView.getMenu(user);
        mapSession.put("Menu", menu.toString());

        StringBuffer dashboardMenu = new StringBuffer("");
        mapSession.put("dbMenu", dashboardMenu.toString());

        return SUCCESS;
    }
}
查看更多
男人必须洒脱
3楼-- · 2019-06-06 03:57

There's no way you can tell between whether the session has timed out or it just hasn't been created yet in your interceptor, unless you add some tracking to your front-end, in primitive case it could be just a single request parameter.

A combination of HttpSessionListener and Servlet3 + AJAX Push notifications would be the right way to do it.

查看更多
登录 后发表回答