Frage

Ich verwende den Yahoo Uploader, einen Teil der Yahoo UI-Bibliothek, auf meiner ASP.Net-Website, um Benutzern das Hochladen von Dateien zu ermöglichen.Für diejenigen, die es nicht kennen: Der Uploader verwendet ein Flash-Applet, um mir mehr Kontrolle über den DateiÖffnen-Dialog zu geben.Ich kann einen Filter für Dateitypen festlegen, die Auswahl mehrerer Dateien zulassen usw.Es ist großartig, weist aber die folgende dokumentierte Einschränkung auf:

Aufgrund eines bekannten Flash-Fehlers sendet der in Firefox unter Windows ausgeführte Uploader beim Upload nicht die richtigen Cookies;Anstatt Firefox-Cookies zu senden, sendet es die Cookies des Internet Explorers für die jeweilige Domain.Um dieses Problem zu umgehen, empfehlen wir, entweder eine Cookie-freie Upload-Methode zu verwenden oder document.cookie an die Upload-Anfrage anzuhängen.

Wenn ein Benutzer also Firefox verwendet, kann ich mich nicht darauf verlassen, dass Cookies die Sitzung aufrechterhalten, wenn er eine Datei hochlädt.Ich brauche ihre Sitzung, weil ich wissen muss, wer sie sind!Als Workaround verwende ich das Application-Objekt folgendermaßen:

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

Also erstelle ich eine eindeutige ID und verwende sie als Schlüssel zum Speichern der Page.User Objekt im Anwendungsbereich.Ich füge diese ID als Variable in den POST ein, wenn die Datei hochgeladen wird.Dann greife ich im Handler, der den Datei-Upload akzeptiert, das User-Objekt folgendermaßen ab:

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

Das funktioniert tatsächlich, hat aber zwei eklatante Nachteile:

  • Wenn IIS, der App-Pool oder auch nur die Anwendung zwischen dem Besuch der Upload-Seite und dem tatsächlichen Hochladen einer Datei durch den Benutzer neu gestartet wird, wird seine „Upload-ID“ aus dem Anwendungsbereich gelöscht und der Upload schlägt fehl, da ich ihn nicht authentifizieren kann .

  • Wenn ich jemals auf ein Webfarm-Szenario (möglicherweise sogar einen Webgarten) skaliere, wird dies völlig kaputt gehen.Ich mache mir vielleicht keine Sorgen, außer dass ich vorhabe, diese App in Zukunft zu skalieren.

Hat jemand einen besseren Weg?Gibt es eine Möglichkeit für mich, die tatsächliche ASP.Net-Sitzungs-ID in einer POST-Variablen zu übergeben und diese ID dann am anderen Ende zum Abrufen der Sitzung zu verwenden?

Ich weiß, dass ich die Sitzungs-ID erhalten kann Session.SessionID, und ich weiß, wie man YUI verwendet, um es auf der nächsten Seite zu veröffentlichen.Was ich nicht weiß, ist, wie ich das nutzen soll SessionID um die Sitzung vom Statusserver abzurufen.

Ja, ich verwende einen Statusserver zum Speichern der Sitzungen, damit sie Anwendungs-/IIS-Neustarts beibehalten und in einem Webfarmszenario funktionieren.

War es hilfreich?

Lösung

Hier ist ein Beitrag vom Betreuer von SWFUpload Hier wird erklärt, wie die Sitzung von einer in Request.Form gespeicherten ID geladen wird.Ich kann mir vorstellen, dass das Gleiche auch für die Yahoo-Komponente funktionieren würde.

Beachten Sie die Sicherheitsausschlüsse am Ende des Beitrags.


Durch das Einfügen einer Global.asax-Datei und des folgenden Codes können Sie das fehlende Sitzungs-ID-Cookie überschreiben:

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

Sicherheitswarnung: Kopieren Sie diesen Code nicht einfach und fügen Sie ihn in Ihre ASP.Net-Anwendung ein, ohne zu wissen, was Sie tun.Es stellt Sicherheitsprobleme und Möglichkeiten des Cross-Site-Scripting vor.

Andere Tipps

Sie können Ihre aktuelle SessionID aus dem folgenden Code erhalten:

string sessionId = HttpContext.Current.Session.SessionID;

Dann können Sie das vielleicht in ein verstecktes Feld eingeben und dann über YUI auf diesen Wert zugreifen.

Es ist nur ein Get, daher werden Sie hoffentlich keine Skalierungsprobleme haben.Allerdings gibt es Sicherheitsprobleme, die ich nicht kenne.

Verlassen auf dieser Blogbeitrag, hier ist eine Funktion, die Ihnen die Sitzung für jeden Benutzer basierend auf der Sitzungs-ID liefern sollte, obwohl sie nicht schön ist:

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;
}

Die ASP.Net-Sitzungs-ID wird in gespeichert Session.SessionID Sie könnten das also in einem versteckten Feld festlegen und es dann auf der nächsten Seite veröffentlichen.

Ich denke jedoch, dass bei einem Neustart der Anwendung die Sitzungs-ID abläuft, wenn Sie dies nicht tun Speichern Sie Ihre Sitzungen auf dem SQL Server.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top