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 が 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に追加します

セッション構成
    セッションタイムアウト 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

私は推測を知りませんが、セッションはインターセプターで利用可能であり、 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を大いに信じていますが、セッションはインターセプターとアクションからかなりアクセスできるので、気にしません.

于 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 に答える