0

在 Jetty 下运行的 Lift 应用程序中实现绝对会话超时的好方法是什么?

我已经有一个空闲超时,但我希望会话最终超时,即使用户从不空闲。

4

2 回答 2

1

首先:您应该知道在活动组件运行时销毁会话的影响(如彗星演员,ajax 请求,...)。但是,一旦检测到会话无效,您也许可以创建一个客户端脚本,该脚本会重定向到您这边的开始/警告页面。LiftRules.noCometSessionCmd并且LiftRules.noAjaxSessionCmd是你的朋友。

现在:您想利用 LiftSessionMaster.sessionCheckFuncs为您提供的机制。它每 10 秒运行一次此方法并为您提供所有当前有效的会话。绝不!存储对会话本身的引用。这就是为什么 lift 为您提供唯一标识符,我们可以利用它。解决方案基于 David Pollack 的代码,用于在高流量高峰时终止会话,您可以在此处找到:https ://www.assembla.com/wiki/show/liftweb/Sessions

在您的 Boot.scala 中添加:

// append forced session timeout to list of checker-funcs
SessionMaster.sessionCheckFuncs = SessionMaster.sessionCheckFuncs 
  ::: List(ForcedSessionTimeout)

然后在你的 lib 包中:

import net.liftweb.common._
import net.liftweb.http.SessionInfo
import net.liftweb.util.Helpers._

object ForcedSessionTimeout extends 
   Function2[Map[String, SessionInfo], SessionInfo => Unit, Unit] 
   with Loggable {

  @volatile var sessionTimeoutMillis: Long = 30 * 60 * 1000 // 30 minutes

  private var firstSeen: Map[String, Long] = Map.empty

  def apply(sessions: Map[String, SessionInfo], destroyer: SessionInfo => Unit): Unit = {
    logger.info("Session check!")
    val timeoutThreshold = millis - sessionTimeoutMillis

    val newFirstSeen: Map[String, Long] = sessions.map {
      case (name, si @ SessionInfo(session, agent, _, cnt, lastAccess)) =>
        firstSeen.get(name) match {
          case Some(firstTimeSeen) =>
            if (firstTimeSeen < timeoutThreshold) {
              logger.info(s" Session $name expired after forced session timeout")
              destroyer(si)
            }
            name -> firstTimeSeen

          case None =>
            // add to first seen list
            name -> millis
        }
    }
    // update first seen map, this prevents a leak if we added a session to the map
    // but lift already expired the session for another reason
    this.firstSeen = newFirstSeen
  }
}
于 2014-03-25T15:09:50.387 回答
0

我会使用 Lifts 功能从头开始构建您想要的东西。一些想法如下:

在内部使用SessionVar带有 TimeoutStorage 的 a(见下文)

将此存储定义为如下所示:

class TimeoutStorage[T] {
    private var inner: Option[(T, Long)] = None // the last argument is when the data was set
    def set {} // set the value. If you want to clear the memory as fast as possible, schedule an erase. Otherwise it would be erased with the `SessionVar` anyway.
    def get{} // check if it has expired
}

如果您想要用户的视觉超时 - 添加一个像 @jcern 说的演员。或者可能只是net.liftweb.util.Schedule一个将 JS 发送到浏览器的小函数(这必须是可能的,尽管应该小心,而不是适当net.liftweb.http.S的范围)。

于 2013-08-24T12:15:36.553 回答