Guice 3.0 @ScopeSession用户对象在会话超时时不会失效

时间:2011-03-12 01:36:58

标签: struts2 guice session-timeout inject

我有一个班级:

@SessionScoped
public class LoggedUser {
    private User user;
    ...
}  

我用来跟踪用户是否已登录我的应用程序。

在我的Struts2应用程序中,我有一个Interceptor来检查用户是否已被登录,如果没有,他会被转发到登录页面。

public class LoggedUserInterceptor extends AbstractInterceptor {

    private static final long serialVersionUID = 2822434409188961460L;

    @Inject
    private LoggedUser loggedUser;

    @Override
    public String intercept(ActionInvocation invocation) throws Exception { 
        if(loggedUser==null || !loggedUser.isLogged()){
            return "login";
        }
        return invocation.invoke();
    }

}

会话超时时出现问题。 LoggdeUser对象永远不会为null或已删除。我总是最后一次。

我添加了一个会话监听器。

public class SessionListener implements HttpSessionListener {

    private static Logger logger = Logger.getLogger(SessionListener.class.getName());

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        logger.info("sessionCreated = " + event.getSession().getId());
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        logger.info("sessionDestroyed = " + event.getSession().getId());
    }

}

我看到sessionDestroyed被调用了,但是当我再次进入我的Interceptor时...... LoggedUser永远不会为新会话重新创建。

为什么?

我的Struts2登录操作是

public class LoginUserAction extends ActionSupport implements ModelDriven<LoggedUser>, ServletRequestAware {
    ...
    @Inject
    private LoggedUser loggedUser;

    public String execute() throws Exception {
        ...
        loggerUser.setLoggedTime(now);
        ...
        return SUCCESS;
    }

我在web.xml中也添加了

session-config
    session-timeout 2 /session-timeout
    /session-config

3 个答案:

答案 0 :(得分:1)

我对Struts2一无所知,但我的猜测是拦截器的范围比会话范围更广。换句话说,拦截器实例的保持时间比会话长。当会话结束时,Guice不能也不会将注入的字段设置为null,也不会自动重新注入对象。

如果在生命周期较长的对象中使用生命周期较短的对象(例如RequestScoped对象内的SessionScoped对象或SessionScoped对象,则需要执行的操作在单身内部)为较短生命的物体注入Provider

在您的情况下,我认为这可能是您所需要的:

public class LoggedUserInterceptor extends AbstractInterceptor {
    private static final long serialVersionUID = 2822434409188961460L;

    @Inject
    private Provider<LoggedUser> loggedUserProvider;

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        LoggedUser loggedUser = loggedUserProvider.get();
        if(loggedUser==null || !loggedUser.isLogged()){
            return "login";
        }
        return invocation.invoke();
    }
}

答案 1 :(得分:0)

我不知道guice但拦截器可以使用会话,并且可以通过SessionAware随时可用于该操作:

ActionInvocation提供对会话的访问。以下是“身份验证”拦截器的一部分。如果没有“User”对象,则返回Action.LOGIN。

public String intercept(ActionInvocation invocation) throws Exception {
    Map session = invocation.getInvocationContext().getSession();
    appLayer.User user = (appLayer.User) session.get("User");
    if (user == null){
        return Action.LOGIN;
    }
    return invocation.invoke();
}

我只在用户登录时将用户对象放在会话上。

在登录操作中,我将用户对象放在会话上:

public class Login extends ActionSupport implements SessionAware {
  private Map<String, Object> session;
  private String userName;
  private String password;

  public String execute() {
    //use DB authentication once this works
    //if ("ken".equalsIgnoreCase(userName) && "ken".equalsIgnoreCase(password)){
    try {
        User user = new User(userName, password);
        session.put("User", user);
        return ActionSupport.SUCCESS;
    } catch (Exception e) {
        System.out.println("There was an exception" + e.getMessage());
        return ActionSupport.LOGIN;
    }
  } 

  public void validate() {
    String user = this.getUserName();
    String pass = this.getPassword();
    //This block is a bit redundant but I couldn't figure out how
    //to get just the hibernate part to report an exception on Username/pass
    if (!StringUtils.isBlank(this.getUserName()) && !StringUtils.isBlank(this.getPassword())) {
        try {
            Class.forName("com.ibm.as400.access.AS400JDBCDriver").newInstance();
            String url = "jdbc:as400://192.168.1.14";
            DriverManager.getConnection(url, user, pass).close();
        } catch (Exception e) {
            addFieldError("login.error.authenticate", "Bad Username / Password");
        }
      }
      if (StringUtils.isBlank(getUserName())) {
        addFieldError("login.error.name", "Missing User Name");
      }
      if (StringUtils.isBlank(getPassword())) {
        addFieldError("login.error.password", "Missing Password");
      }
    //else both are blank don't report an error at this time
  }

  ... getters/setters....
  }//end class

如果我没记错的话,至少部分来自“Struts2 in Action”。无论如何,我是DI的忠实信徒,但是因为会话很容易从拦截器和我不打扰的行动中获取。

答案 2 :(得分:0)

最简单的方法是最终将令牌放在登录会话中并使用拦截器进行检查

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

        loggedUser = (LoggedUser) invocation.getInvocationContext().getSession().get(LoggedUser.SESSIONTOKEN);

        if(loggedUser==null || !loggedUser.isLogged()){
            logger.info("loggedUser not present in session");
            return "login";
        }

        return invocation.invoke();
    }

行动中的

request.getSession().setAttribute(LoggedUser.SESSIONTOKEN, loggedUser);