如何使用 JSESSIONID 手动加载 Java 会话?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1499581/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I manually load a Java session using a JSESSIONID?
提问by Robert Campbell
I have a servlet which handles a multipart form post. The post is actually being made by a Flash file upload component embedded in the page. In some browsers, the Flash-generated POST doesn't include the JSESSIONID which is making it impossible for me to load certain information from the session during the post.
我有一个处理多部分表单帖子的 servlet。该帖子实际上是由嵌入在页面中的 Flash 文件上传组件制作的。在某些浏览器中,Flash 生成的 POST 不包含 JSESSIONID,这使我无法在发布期间从会话中加载某些信息。
The flash upload component does include cookie and session information within a special form field. Using this form field, I can actually retrieve the JSESSIONID value. The problem is, I don't know how to use this JSESSIONID value to manually load that specific session.
Flash 上传组件在一个特殊的表单字段中包含 cookie 和会话信息。使用此表单字段,我实际上可以检索 JSESSIONID 值。问题是,我不知道如何使用这个 JSESSIONID 值来手动加载该特定会话。
Edit -Based on ChssPly76's solution, I created the following HttpSessionListenerimplementation:
编辑 -基于 ChssPly76 的解决方案,我创建了以下HttpSessionListener实现:
@Override
public void sessionCreated(final HttpSessionEvent se) {
final HttpSession session = se.getSession();
final ServletContext context = session.getServletContext();
context.setAttribute(session.getId(), session);
}
@Override
public void sessionDestroyed(final HttpSessionEvent se) {
final HttpSession session = se.getSession();
final ServletContext context = session.getServletContext();
context.removeAttribute(session.getId());
}
Which adds all sessions to the ServletContextas attributes mapped by their unique ids. I could put a Map of sessions in the context instead, but it seems redundant. Please post any thoughts on this decision. Next, I add the following method to my servlet to resolve the session by id:
它将所有会话添加到ServletContext作为由其唯一 id 映射的属性。我可以在上下文中放置一个会话地图,但这似乎是多余的。请发表对此决定的任何想法。接下来,我将以下方法添加到我的 servlet 以通过 id 解析会话:
private HttpSession getSession(final String sessionId) {
final ServletContext context = getServletContext();
final HttpSession session = (HttpSession) context.getAttribute(sessionId);
return session;
}
采纳答案by ChssPly76
There is no API to retrieve session by id.
没有通过 id 检索会话的 API。
What you can do, however, is implement a session listenerin your web application and manually maintain a map of sessions keyed by id (session id is retrievable via session.getId()). You will then be able to retrieve any session you want (as opposed to tricking container into replacing your current session with it as others suggested)
但是,您可以做的是在您的 Web 应用程序中实现会话侦听器并手动维护由 id 键控的会话映射(会话 id 可通过session.getId()检索)。然后,您将能够检索您想要的任何会话(而不是像其他人建议的那样欺骗容器用它替换您当前的会话)
回答by Andrew Duffy
There is no way within the servlet spec, but you could try:
servlet 规范中没有办法,但您可以尝试:
manually setting the cookie in the request made by Flash
or doing as Taylor L just suggested as I was typing and adding the jsessionid parameter the path of the URI.
在 Flash 发出的请求中手动设置 cookie
或者按照 Taylor L 刚刚建议的那样做,因为我正在键入并将 jsessionid 参数添加到 URI 的路径中。
Both methods will tie your app to running on a servlet container that behaves like Tomcat; I think most of them do. Both will also require your Flash applet asking the page for its cookies, which may impose a JavaScript dependency.
这两种方法都会将您的应用程序绑定到在行为类似于 Tomcat 的 servlet 容器上运行;我认为他们中的大多数人都这样做。两者都还需要您的 Flash 小程序向页面询问其 cookie,这可能会强加 JavaScript 依赖性。
回答by Garfield
This is a really good post. One potential issue I see with using the session listener to keep adding sessions to the context is that it can get quite fat depending on the number of concurrent sessions you have. And then all the additional work for the web server configuration for the listener.
这是一个非常好的帖子。我看到使用会话侦听器不断向上下文添加会话的一个潜在问题是,根据您拥有的并发会话数量,它可能会变得非常胖。然后是为侦听器配置 Web 服务器的所有额外工作。
So how about this for a much simpler solution. I did implement this and it works quite well. So on the page that loads the flash upload object, store the session and sessionid as a key-value pair in the application object then pass that session id to the upload page as a post parameter. The on the upload page, see if that sessionid is already in the application, is so use that session, otherwise, get the one from the request. Also, then go ahead and remove that key from the application to keep everything clean.
那么对于一个更简单的解决方案如何。我确实实现了这一点,并且效果很好。因此,在加载 Flash 上传对象的页面上,将 session 和 sessionid 作为键值对存储在应用程序对象中,然后将该会话 id 作为 post 参数传递给上传页面。在上传页面上,查看该 sessionid 是否已经在应用程序中,所以使用该 session,否则,从请求中获取。此外,然后继续从应用程序中删除该密钥以保持一切清洁。
On the swf page:
在 swf 页面上:
application.setAttribute(session.getId(), session);
Then on the upload page:
然后在上传页面:
String sessid = request.getAttribute("JSESSIONID");
HttpSession sess = application.getAttribute(sessid) == null ?
request.getSession() :
(HttpSession)application.getAttribute(sessid);
application.removeAttribute(sessid);
Very nice solution guys. Thanks for this.
非常好的解决方案伙计们。谢谢你。
回答by vanval
A safe way to do it is to set the jsession id in the cookie - this is much safer than setting it in the url.
一种安全的方法是在 cookie 中设置 jsession id - 这比在 url 中设置它安全得多。
Once it is set as a cookie, then you can retrieve the session in the normal way using
一旦将其设置为 cookie,您就可以使用正常方式检索会话
request.getSession();
method.setRequestHeader("Cookie", "JSESSIONID=88640D6279B80F3E34B9A529D9494E09");
回答by Sam Sieber
If you are using Tomcat, you ask tomcat directly (but it's ugly). I bet there are other hacky solutions for other web servers.
如果你用的是Tomcat,你直接问tomcat(但是很丑)。我敢打赌,其他 Web 服务器还有其他 hacky 解决方案。
It uses an instance of the "Manager" interface to manage the sessions. What makes it ugly is that I haven't found a nice public interface to be able to hook into, so we have to use reflection to get the manager.
它使用“Manager”接口的一个实例来管理会话。丑陋的是我还没有找到一个很好的公共接口可以挂钩,所以我们必须使用反射来获取管理器。
Below is a context listener that grabs that manager on context startup, and then can be used to get the Tomcat Session.
下面是一个上下文侦听器,它在上下文启动时获取该管理器,然后可用于获取 Tomcat 会话。
public class SessionManagerShim implements ServletContextListener {
static Manager manager;
@Override
public void contextInitialized(ServletContextEvent sce) {
try {
manager = getManagerFromServletContextEvent(sce);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
manager = null;
}
private static Manager getManagerFromServletContextEvent(ServletContextEvent sce) throws NoSuchFieldException, IllegalAccessException {
// Step one - get the ApplicationContextFacade (Tomcat loves facades)
ApplicationContextFacade contextFacade = (ApplicationContextFacade)sce.getSource();
// Step two - get the ApplicationContext the facade wraps
Field appContextField = ApplicationContextFacade.class.getDeclaredField("context");
appContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext)
appContextField.get(contextFacade);
// Step three - get the Context (a tomcat context class) from the facade
Field contextField = ApplicationContext.class.getDeclaredField("context");
contextField.setAccessible(true);
Context context = (Context) contextField.get(applicationContext);
// Step four - get the Manager. This is the class Tomcat uses to manage sessions
return context.getManager();
}
public static Session getSession(String sessionID) throws IOException {
return manager.findSession(sessionID);
}
}
You can add this as a listener in your web.xml and it should work.
您可以将其添加为 web.xml 中的侦听器,它应该可以工作。
Then you could do this to get a session.
然后你可以这样做来获得一个会话。