0

我有一堂课:

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

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

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

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 永远不会为空或被删除。我总是最后一个例子。

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

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 中添加了它

会话配置
    会话超时 2 /会话超时
    /会话配置
4

3 回答 3

1

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

如果在生命周期较长的对象(例如RequestScoped对象内的SessionScoped对象或SessionScoped单例内的对象)中使用生命周期较短的对象,则需要为较短生命周期的对象注入 a 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();
    }
}
于 2011-03-12T14:22:18.470 回答
0

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

ActionInvocation 提供对会话的访问。以下是“身份验证”拦截器的一部分。如果没有“用户”对象,则返回 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 的忠实信徒,但由于 Session 可以从拦截器和操作中轻松访问,因此我不打扰。

于 2011-03-12T05:37:50.300 回答
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);

于 2011-04-11T22:03:45.130 回答