如何使用 JSESSIONID 手动加载 Java 会话?

发布于 2024-08-07 03:56:39 字数 1265 浏览 11 评论 0原文

我有一个处理多部分表单帖子的 servlet。该帖子实际上是由嵌入在页面中的 Flash 文件上传组件制作的。在某些浏览器中,Flash 生成的 POST 不包含 JSESSIONID,这使得我无法在发布期间从会话加载某些信息。

Flash 上传组件确实在特殊表单字段中包含 cookie 和会话信息。使用此表单字段,我实际上可以检索 JSESSIONID 值。问题是,我不知道如何使用这个 JSESSIONID 值来手动加载该特定会话。

编辑 - 基于 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());
    }

它将所有会话添加到 ServletContext 作为由其唯一 ID 映射的属性。我可以在上下文中放置一个会话映射,但这似乎是多余的。请发表对此决定的任何想法。接下来,我将以下方法添加到我的 servlet 中以通过 id 解析会话:

    private HttpSession getSession(final String sessionId) {
        final ServletContext context = getServletContext();
        final HttpSession session = (HttpSession) context.getAttribute(sessionId);
        return session;
    }

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.

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.

Edit - Based on ChssPly76's solution, I created the following HttpSessionListener implementation:

    @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 ServletContext as 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:

    private HttpSession getSession(final String sessionId) {
        final ServletContext context = getServletContext();
        final HttpSession session = (HttpSession) context.getAttribute(sessionId);
        return session;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心病无药医 2024-08-14 03:56:39

没有 API 可以通过 id 检索会话。

但是,您可以做的是实现 会话在您的 Web 应用程序中添加监听器,并手动维护以 id 为键的会话映射(会话 id 可通过 session.getId())。然后,您将能够检索您想要的任何会话(而不是像其他人建议的那样欺骗容器用它替换当前会话)

There is no API to retrieve session by id.

What you can do, however, is implement a session listener in 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)

暮倦 2024-08-14 03:56:39

一种安全的方法是在 cookie 中设置 jsession id - 这比在 url 中设置要安全得多。

一旦将其设置为 cookie,您就可以使用正常方式检索会话

request.getSession();

method.setRequestHeader("Cookie", "JSESSIONID=88640D6279B80F3E34B9A529D9494E09");

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.

Once it is set as a cookie, then you can retrieve the session in the normal way using

request.getSession();

method.setRequestHeader("Cookie", "JSESSIONID=88640D6279B80F3E34B9A529D9494E09");
丶视觉 2024-08-14 03:56:39

如果你使用的是Tomcat,你直接询问tomcat(但它很难看)。我敢打赌还有其他针对其他网络服务器的黑客解决方案。

它使用“管理器”界面的实例来管理会话。让它丑陋的是,我还没有找到一个很好的公共接口来连接,所以我们必须使用反射来获取管理器。

下面是一个上下文侦听器,它在上下文启动时获取该管理器,然后可用于获取 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);
    }
}

您可以将其添加为 web.xml 中的侦听器,它应该可以工作。

然后你可以这样做来获得一个会话。

If you are using Tomcat, you ask tomcat directly (but it's ugly). I bet there are other hacky solutions for other web servers.

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.

Below is a context listener that grabs that manager on context startup, and then can be used to get the Tomcat Session.

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.

Then you could do this to get a session.

骄傲 2024-08-14 03:56:39

servlet 规范中没有办法,但您可以尝试:

  • 在 Flash 发出的请求中手动设置 cookie

  • 或者像 Taylor L 那样做在我键入并添加 jsessionid 参数 URI 的路径时建议。

这两种方法都会将您的应用程序绑定到运行在行为类似于 Tomcat 的 servlet 容器上;我想他们大多数人都是这样的。两者都还需要您的 Flash 小程序向页面询问其 cookie,这可能会强加 JavaScript 依赖性。

There is no way within the servlet spec, but you could try:

  • 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.

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.

山色无中 2024-08-14 03:56:39

这是一篇非常好的帖子。我发现使用会话侦听器不断向上下文添加会话的一个潜在问题是,根据并发会话的数量,它可能会变得相当庞大。然后是侦听器的 Web 服务器配置的所有额外工作。

那么,如果有一个更简单的解决方案怎么样?我确实实现了这个并且效果很好。因此,在加载 Flash 上传对象的页面上,将 session 和 sessionid 作为键值对存储在应用程序对象中,然后将该 session id 作为 post 参数传递到上传页面。在上传页面上,查看该 sessionid 是否已在应用程序中,因此使用该会话,否则,从请求中获取该会话。另外,然后继续从应用程序中删除该密钥以保持一切干净。

在 swf 页面上:

application.setAttribute(session.getId(), session);

然后在上传页面上:

String sessid = request.getAttribute("JSESSIONID");
HttpSession sess = application.getAttribute(sessid) == null ?
        request.getSession() :
        (HttpSession)application.getAttribute(sessid);
application.removeAttribute(sessid);

非常好的解决方案。谢谢你。

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.

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.

On the swf page:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文