web-dev-qa-db-fra.com

Comment charger manuellement une session Java avec un JSESSIONID?

J'ai un servlet qui gère un post de formulaire multipart. La publication est en fait réalisée par un composant de téléchargement de fichier Flash intégré à la page. Dans certains navigateurs, le POST généré par Flash n'inclut pas le JSESSIONID, ce qui m'empêche de charger certaines informations de la session pendant le post. 

Le composant de téléchargement flash inclut les cookies et les informations de session dans un champ de formulaire spécial. En utilisant ce champ de formulaire, je peux réellement récupérer la valeur JSESSIONID. Le problème est que je ne sais pas comment utiliser cette valeur JSESSIONID pour charger manuellement cette session spécifique.

Edit - Sur la base de la solution de ChssPly76, j'ai créé l'implémentation suivante de 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());
    }

Qui ajoute toutes les sessions à ServletContext en tant qu'attributs mappés par leurs identifiants uniques. Je pourrais mettre une carte des sessions dans le contexte à la place, mais cela semble redondant. S'il vous plaît poster des pensées sur cette décision. Ensuite, j'ajoute la méthode suivante à mon servlet pour résoudre la session par identifiant:

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

Il n'y a pas d'API pour récupérer une session par identifiant.

Ce que vous pouvez faire, cependant, est d'implémenter un session listener dans votre application Web et de maintenir manuellement une carte des sessions indexées par id (l'id de session est récupérable via session.getId () ). Vous pourrez alors récupérer n'importe quelle session de votre choix (par opposition à inciter le conteneur à remplacer votre session actuelle par son remplacement, comme suggéré par d'autres)

23
ChssPly76

Un moyen sûr de le faire est de définir l’identifiant jsession dans le cookie - c’est beaucoup plus sûr que de le définir dans l’URL.

Une fois défini comme cookie, vous pouvez récupérer la session de la manière habituelle en utilisant 

request.getSession();

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

Il n'y a aucun moyen dans les spécifications de servlet, mais vous pouvez essayer:

  • définir manuellement le cookie dans la demande faite par Flash

  • ou faire comme Taylor L vient de le suggérer alors que je tapais et que j'ajoutais le paramètre jsessionid au chemin de l'URI.

Les deux méthodes lieront votre application à une exécution sur un conteneur de servlet qui se comporte comme Tomcat; Je pense que la plupart d'entre eux le font. Les deux nécessitent également que votre applet Flash demande à la page ses cookies, qui peuvent imposer une dépendance à JavaScript.

1
Andrew Duffy

Si vous utilisez Tomcat, vous demandez à Tomcat directement (mais c'est moche). Je parie qu'il existe d'autres solutions de hacky pour d'autres serveurs Web.

Il utilise une instance de l'interface "Manager" pour gérer les sessions. Ce qui le rend laid, c'est que je n'ai pas trouvé d'interface publique agréable pour pouvoir y accéder, nous devons donc utiliser la réflexion pour obtenir le manager.

Vous trouverez ci-dessous un écouteur de contexte qui récupère ce gestionnaire au démarrage du contexte et peut ensuite être utilisé pour obtenir la 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);
    }
}

Vous pouvez ajouter ceci en tant qu'écouteur dans votre web.xml et cela devrait fonctionner.

Ensuite, vous pouvez le faire pour obtenir une session.

0
Sam Sieber

C'est un très bon post. Un problème potentiel que je vois avec l'utilisation du programme d'écoute de session pour continuer à ajouter des sessions au contexte est qu'il peut devenir assez gros en fonction du nombre de sessions simultanées que vous avez. Et puis tout le travail supplémentaire pour la configuration du serveur Web pour l'écouteur.

Alors, que diriez-vous de cela pour une solution beaucoup plus simple. J'ai implémenté ceci et cela fonctionne assez bien. Ainsi, sur la page qui charge l'objet de téléchargement flash, stockez la session et sessionid en tant que paire clé-valeur dans l'objet d'application, puis transmettez cet ID de session à la page de téléchargement en tant que paramètre de publication. Sur la page de téléchargement, voyez si cet identifiant de session est déjà dans l'application, utilisez donc cette session. Sinon, récupérez celui-ci à partir de la demande. En outre, supprimez cette clé de l'application pour que tout reste propre.

Sur la page swf:

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

Puis sur la page de téléchargement:

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

Très belle solution les gars. Merci pour cela.

0
Garfield