Domanda

Sto utilizzando Yahoo Uploader, parte della Yahoo UI Library, sul mio sito Web ASP.Net per consentire agli utenti di caricare file.Per chi non lo conosce, l'uploader funziona utilizzando un'applet Flash per darmi un maggiore controllo sulla finestra di dialogo FileOpen.Posso specificare un filtro per i tipi di file, consentire la selezione di più file, ecc.È fantastico, ma presenta la seguente limitazione documentata:

A causa di un noto bug di Flash, l'Uploader in esecuzione in Firefox in Windows non invia i cookie corretti con il caricamento;invece di inviare i cookie di Firefox, invia i cookie di Internet Explorer per il rispettivo dominio.Come soluzione alternativa, suggeriamo di utilizzare un metodo di caricamento senza cookie o di aggiungere document.cookie alla richiesta di caricamento.

Pertanto, se un utente utilizza Firefox, non posso fare affidamento sui cookie per mantenere la sessione quando carica un file.Ho bisogno della loro sessione perché ho bisogno di sapere chi sono!Come soluzione alternativa, sto utilizzando l'oggetto Application in questo modo:

Guid UploadID = Guid.NewGuid();
Application.Add(Guid.ToString(), User);

Quindi, sto creando un ID univoco e lo utilizzo come chiave per archiviare il file Page.User oggetto nell'ambito dell'applicazione.Includo quell'ID come variabile nel POST quando il file viene caricato.Quindi, nel gestore che accetta il caricamento del file, prendo l'oggetto Utente in questo modo:

IPrincipal User = (IPrincipal)Application[Request.Form["uploadid"]];

In realtà funziona, ma presenta due evidenti inconvenienti:

  • Se IIS, il pool di app o anche solo l'applicazione vengono riavviati tra il momento in cui l'utente visita la pagina di caricamento e carica effettivamente un file, il loro "uploadid" viene eliminato dall'ambito dell'applicazione e il caricamento non riesce perché non riesco ad autenticarli .

  • Se mai dovessi passare a uno scenario di web farm (possibilmente anche un web garden), questo si romperebbe completamente.Potrei non essere preoccupato, tranne che ho intenzione di ridimensionare questa app in futuro.

Qualcuno ha un modo migliore?Esiste un modo per passare l'ID sessione ASP.Net effettivo in una variabile POST, quindi utilizzare quell'ID all'altra estremità per recuperare la sessione?

So che posso ottenere l'ID della sessione Session.SessionID, e so come utilizzare YUI per pubblicarlo nella pagina successiva.Quello che non so è come usarlo SessionID per prendere la sessione dal server di stato.

Sì, sto utilizzando un server di stato per archiviare le sessioni, in modo che persistano i riavvii dell'applicazione/IIS e funzionino in uno scenario di web farm.

È stato utile?

Soluzione

Qui è un post del manutentore di SWFCarica che spiega come caricare la sessione da un ID memorizzato in Request.Form.Immagino che la stessa cosa funzionerebbe per il componente Yahoo.

Nota le esclusioni di responsabilità sulla sicurezza in fondo al post.


Includendo un file Global.asax e il seguente codice è possibile sovrascrivere il cookie ID sessione mancante:

using System;
using System.Web;

public class Global_asax : System.Web.HttpApplication
{
    private void Application_BeginRequest(object sender, EventArgs e)
    {
        /* 
        Fix for the Flash Player Cookie bug in Non-IE browsers.
        Since Flash Player always sends the IE cookies even in FireFox
        we have to bypass the cookies by sending the values as part of the POST or GET
        and overwrite the cookies with the passed in values.

        The theory is that at this point (BeginRequest) the cookies have not been ready by
        the Session and Authentication logic and if we update the cookies here we'll get our
        Session and Authentication restored correctly
        */

        HttpRequest request = HttpContext.Current.Request;

        try
        {
            string sessionParamName = "ASPSESSID";
            string sessionCookieName = "ASP.NET_SESSIONID";

            string sessionValue = request.Form[sessionParamName] ?? request.QueryString[sessionParamName];
            if (sessionValue != null)
            {
                UpdateCookie(sessionCookieName, sessionValue);
            }
        }
        catch (Exception ex)
        {
            // TODO: Add logging here.
        }

        try
        {
            string authParamName = "AUTHID";
            string authCookieName = FormsAuthentication.FormsCookieName;

            string authValue = request.Form[authParamName] ?? request.QueryString[authParamName];
            if (authValue != null)
            {
                UpdateCookie(authCookieName, authValue);
            }
        }
        catch (Exception ex)
        {
            // TODO: Add logging here.
        }
    }

    private void UpdateCookie(string cookieName, string cookieValue)
    {
        HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookieName);
        if (cookie == null)
        {
            HttpCookie newCookie = new HttpCookie(cookieName, cookieValue);
            Response.Cookies.Add(newCookie);
        }
        else
        {
            cookie.Value = cookieValue;
            HttpContext.Current.Request.Cookies.Set(cookie);
        }
    }
}

Avviso di sicurezza: Non limitarti a copiare e incollare questo codice nella tua applicazione ASP.Net senza sapere cosa stai facendo.Introduce problemi di sicurezza e possibilità di Cross-site Scripting.

Altri suggerimenti

Puoi ottenere il tuo SessionID corrente dal seguente codice:

string sessionId = HttpContext.Current.Session.SessionID;

Quindi puoi magari inserirlo in un campo nascosto e quindi accedere a quel valore tramite YUI.

È solo un guadagno, quindi spero che non avrai problemi di ridimensionamento.Problemi di sicurezza però, questo non lo so.

Contare su questo post del blog, ecco una funzione che dovrebbe fornirti la sessione per qualsiasi utente in base all'ID sessione, anche se non è carina:

public SessionStateStoreData GetSessionById(string sessionId)
{
    HttpApplication httpApplication = HttpContext.ApplicationInstance;

    // Black magic #1: getting to SessionStateModule
    HttpModuleCollection httpModuleCollection = httpApplication.Modules;
    SessionStateModule sessionHttpModule = httpModuleCollection["Session"] as SessionStateModule;
    if (sessionHttpModule == null)
    {
        // Couldn't find Session module
        return null;
    }

    // Black magic #2: getting to SessionStateStoreProviderBase through reflection
    FieldInfo fieldInfo = typeof(SessionStateModule).GetField("_store", BindingFlags.NonPublic | BindingFlags.Instance);
    SessionStateStoreProviderBase sessionStateStoreProviderBase = fieldInfo.GetValue(sessionHttpModule) as SessionStateStoreProviderBase;
    if (sessionStateStoreProviderBase == null)
    {
        // Couldn't find sessionStateStoreProviderBase
        return null;
    }

    // Black magic #3: generating dummy HttpContext out of the thin air. sessionStateStoreProviderBase.GetItem in #4 needs it.
    SimpleWorkerRequest request = new SimpleWorkerRequest("dummy.html", null, new StringWriter());
    HttpContext context = new HttpContext(request);

    // Black magic #4: using sessionStateStoreProviderBase.GetItem to fetch the data from session with given Id.
    bool locked;
    TimeSpan lockAge;
    object lockId;
    SessionStateActions actions;
    SessionStateStoreData sessionStateStoreData = sessionStateStoreProviderBase.GetItem(
        context, sessionId, out locked, out lockAge, out lockId, out actions);
    return sessionStateStoreData;
}

L'ID sessione ASP.Net è archiviato in Session.SessionID quindi potresti impostarlo in un campo nascosto e poi pubblicarlo nella pagina successiva.

Penso, tuttavia, che se l'applicazione si riavvia, il sessionID scadrà in caso contrario memorizza le tue sessioni in SQL Server.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top