在我的Tomcat 7.0上使用Spring Web MVC运行的应用程序中,我有一些控制器,尽管对它们的请求需要身份验证和有效会话,但我不希望更新会话的到期时间戳。换句话说,我希望会话准确到期,否则会发生此特定HTTP请求。
这些是AJAX方法,如果它很重要,虽然我不知道它是否。
可以通过通用Java EE或一些特殊的Tomcat挂钩来完成吗?还有另一种方法来实现这一目标吗?我知道http://download.oracle.com/javaee/6/api/javax/servlet/http/HttpSession.html#setMaxInactiveInterval%28int%29,但这似乎与我想要的完全相反。
答案 0 :(得分:2)
HttpServletRequest#getSession
时, 访问时间仅更新为 。因此,如果您确定没有篡改会话,那么您应该没问题。 更新:基于the JavaDoc上述情况并非如此(即使您搜索了源代码代码彻底,并没有发现任何代码负责此类行为。)
另一方面,如果你需要在AJAX请求中访问会话,那么你几乎搞砸了。我能想到的唯一解决方案是手动存储lastAccessTime
(例如在servlet过滤器中),然后检查会话超时和invalidate the session manually(例如在同一过滤器中)。这应该非常简单易行。
更新:为了实现过滤器的乐趣(未经过测试):
public class SessionInvalidationFilter implements Filter {
private static final String LAST_ACCESS_SESSION_ATTR = "lastAccessTime";
private static final long SESSION_TIMEOUT = 1000 * 60 * 20; // 20 minutes
private static final String IGNORE_ACCESS_URI = "/this/will-not/update/access-time";
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Cast to HTTP request and response
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Check if we are handling standard request
if (!IGNORE_ACCESS_URI.equals(httpRequest.getRequestURI())) {
chain.doFilter(new SessionAccessAwareRequest(httpRequest), response);
return;
}
// Now we can handle the special case of non-tracked request
boolean expired = false;
HttpSession session = httpRequest.getSession(false);
if (session == null) {
// No session means the AJAX contained no or incorrect JSESSIONID
expired = true;
} else {
Long lastAccessTime = (Long) session.getAttribute(LAST_ACCESS_SESSION_ATTR);
if (lastAccessTime == null || lastAccessTime + SESSION_TIMEOUT < System.currentTimeMillis()) {
session.invalidate(); // Invalidate manually
expired = true;
}
}
// Handle error or process normally
if (expired) {
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
} else {
chain.doFilter(request, response);
}
}
private static class SessionAccessAwareRequest extends HttpServletRequestWrapper {
public SessionAccessAwareRequest(HttpServletRequest request) {
super(request);
}
@Override
public HttpSession getSession() {
return getSession(true);
}
@Override
public HttpSession getSession(boolean create) {
HttpSession session = super.getSession(create);
if (session != null) {
session.setAttribute(LAST_ACCESS_SESSION_ATTR, System.currentTimeMillis());
}
return session;
}
}
}
答案 1 :(得分:0)
不。 在Spring和您的应用程序有机会处理来自当前用户浏览器的HTTP请求之前,tomcat已根据Servlet规范更新了当前用户的会话。因此,Spring和您的应用程序无法控制续订当前用户的会话。
servlet-3_1-final.pdf的“ 7.6最后访问时间”显示为“ 当会话的一部分的请求首先由Servlet容器处理时,就认为该会话已被访问。”
如果Tomcat是Servlet容器。
调用Request.getSession()
或getSession(boolean create)
时:
看到
Line 2955 of Request.java
和
Line 269 of Session.java
据说
“/**
* Update the accessed time information for this session. This method
* should be called by the context when a request comes in for a particular
* session, even if the application does not reference it.
*/“
相关的已实现类Line 675 of StandardSession.java
调用Request.getSession()
或getSession(boolean create)
后,现有会话将通过更新thisAccessedTime
共享了一个调试过程,以查看现有会话的更新位置
操作:
请参见Line 511 of org.apache.catalina.authenticator.AuthenticatorBase 请参阅https://imgur.com/a/QJ3IJxh,它将逻辑显示为
timeNow - thisAccessedTime
thisAccessedTime
。
这是更新会话的第一个地方,也是唯一的地方在此方法上的以下调用不会调用access(),这可以在以下时间看到
在Line 541 of org.apache.catalina.authenticator.AuthenticatorBase过滤器链处理中继续HTTP请求处理进度 Line 110 of org.springframework.security.web.context.HttpSessionSecurityContextRepository.java 和Line 130 of org.springframework.security.web.session.ConcurrentSessionFilter.java 参见https://imgur.com/a/MfjJ2ey
只有Tomcat可以控制更新thisAccessedTime
以续订现有会话的有效时间。
实际上,目标是使效果看起来像某些特殊的HTTP请求(某些特殊的API,URL)无法续订在线用户会话,结果,如果只剩下这些API调用,就没有更多了其他正常的API调用会在有效的会话间隔内出现,然后使会话无效。
在选择以下选项之一之前,需要根据您的方案进行权衡
A>找到一个切入点,可以选择
javax.servlet.Fitler
的自定义实现
Servlet上下文过滤器链的末端org.springframework.web.filter.GenericFilterBean
位于末尾
Sprint内部过滤器链的过滤器链。org.springframework.web.servlet.HandlerInterceptor
然后
thisAccessedTime
thisAccessedTime
检查会话是否仍然有效。如果已过期,则使会话无效 B>在Servlet上下文的过滤器链的末尾,javax.servlet.Fitler
的定制过滤器实现
用完全自定义的会话生存期和会话事件实现包装Request.getSession()
和getSession(boolean create)
。
C> Websocket和Long Polling进行实时通信