2009-09-30 11 views
25

Ho un servlet che gestisce un post di modulo multiparte. Il post viene effettivamente creato da un componente di caricamento di file Flash incorporato nella pagina. In alcuni browser, il POST generato da Flash non include JSESSIONID che mi impedisce di caricare determinate informazioni dalla sessione durante il post.Come posso caricare manualmente una sessione Java usando un JSESSIONID?

Il componente di caricamento flash include informazioni su cookie e sessione all'interno di un campo modulo speciale. Utilizzando questo campo modulo, posso effettivamente recuperare il valore JSESSIONID. Il problema è che non so come usare questo valore JSESSIONID per caricare manualmente quella specifica sessione.

Edit - Sulla base di soluzione di ChssPly76, ho creato il seguente HttpSessionListener implementazione:

@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()); 
    } 

che aggiunge tutte le sessioni al ServletContext come attributi mappati dai loro ID univoci. Potrei inserire una mappa di sessioni nel contesto, ma sembra ridondante. Si prega di postare qualsiasi pensiero su questa decisione. Successivamente, ho aggiungere il seguente metodo alla mia servlet per risolvere la sessione ID:

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

+1 .. molto bella domanda – peakit

risposta

21

Non esiste alcuna API per recuperare la sessione dall'ID.

Ciò che è possibile fare, tuttavia, è implementare un session listener nell'applicazione Web e mantenere manualmente una mappa di sessioni immesse per id (ID di sessione è recuperabile tramite session.getId()). Sarai quindi in grado di recuperare qualsiasi sessione tu voglia (al posto del contenitore ingannevole sostituendo la tua sessione corrente con quella suggerita da altri)

+0

Questo è intelligente. –

+1

La mia unica preoccupazione è la porzione di errore umano in cui uno sviluppatore introdurrà del codice utilizzando request.getSession() anziché utilizzare la mappa degli ID di sessione. Credo che la soluzione "più semplice" sia quella di costruire l'URL in modo appropriato. –

+0

Due modi in cui posso immaginare il servlet che chiede al listener la mappa di sessione: listener è un singleton o posiziona la mappa nel ServletContext – rcampbell

1

Non c'è modo all'interno della specifica servlet, ma si potrebbe provare:

  • impostare manualmente il cookie in la richiesta fatta da Flash

  • o come Taylor L ha appena suggerito mentre stavo digitando e aggiungendo il parametro jsessionid il percorso dell'URI.

Entrambi i metodi collegheranno l'app in esecuzione su un contenitore servlet che si comporta come Tomcat; Penso che la maggior parte di loro lo faccia. Entrambi richiedono anche l'applet Flash che chiede alla pagina i suoi cookie, che potrebbero imporre una dipendenza JavaScript.

0

Questo è un post davvero buono. Un potenziale problema che vedo con l'uso del listener di sessioni per continuare ad aggiungere sessioni al contesto è che può diventare piuttosto grasso a seconda del numero di sessioni simultanee che si hanno. E poi tutto il lavoro aggiuntivo per la configurazione del server web per il listener.

Che ne dici di una soluzione molto più semplice. L'ho implementato e funziona abbastanza bene. Pertanto, nella pagina in cui viene caricato l'oggetto di caricamento flash, memorizzare la sessione e l'id di sessione come coppia valore-chiave nell'oggetto applicazione, quindi passare l'ID di sessione alla pagina di caricamento come parametro post. Nella pagina di caricamento, controlla se quel sessionid è già presente nell'applicazione, quindi usa quella sessione, altrimenti, ottieni quello dalla richiesta. Inoltre, andare avanti e rimuovere quella chiave dall'applicazione per mantenere tutto pulito.

Nella pagina swf:

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

Poi sulla pagina di upload:

Molto bravi ragazzi soluzione. Grazie per questo.

+5

"abbastanza grasso"? L'hai misurato? Hai familiarità con Java? È solo un riferimento, non una copia del valore ... – BalusC

+0

Oops, hai ragione. Non pensavo che attraverso. Ancora, più facile da attuare che il suggerimento originale. Inoltre, dal momento che ho completamente testato questo codice ora, ho trovato il seguente. Se il poster originale si riferiva specificamente a SWFUpload, quando carichi più di un file, SWFUpload pubblicherà ogni file singolarmente, non tutti in un solo post. Quindi rimuovendo il modulo di sessione dall'oggetto applicazione dopo il primo caricamento, tutti gli altri falliscono. FYI. – Garfield

2

Un modo sicuro per farlo è impostare l'ID jsession nel cookie: è molto più sicuro che impostarlo nell'URL.

Una volta che è impostato come un biscotto, allora è possibile recuperare la sessione in modo normale utilizzando

request.getSession(); 

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

Se si utilizza Tomcat, si chiede Tomcat direttamente (ma è brutto). Scommetto che ci sono altre soluzioni hacky per altri server web.

Utilizza un'istanza dell'interfaccia "Manager" per gestire le sessioni. Ciò che lo rende brutto è che non ho trovato una bella interfaccia pubblica per essere in grado di connettersi, quindi dobbiamo usare la riflessione per ottenere il manager.

Di seguito è un listener di contesto che acquisisce tale gestore all'avvio del contesto e quindi può essere utilizzato per ottenere la 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); 
    } 
} 

È possibile aggiungere questo come listener nel proprio file web.xml e dovrebbe funzionare.

Quindi è possibile eseguire questa operazione per ottenere una sessione.