在 Jetty 下运行的 Lift 应用程序中实现绝对会话超时的好方法是什么?
我已经有一个空闲超时,但我希望会话最终超时,即使用户从不空闲。
在 Jetty 下运行的 Lift 应用程序中实现绝对会话超时的好方法是什么?
我已经有一个空闲超时,但我希望会话最终超时,即使用户从不空闲。
首先:您应该知道在活动组件运行时销毁会话的影响(如彗星演员,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
}
}
我会使用 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
的范围)。