2008-09-04 19 views
9

Estoy usando Yahoo Uploader, parte de la biblioteca Yahoo UI, en mi sitio web ASP.Net para permitir que los usuarios carguen archivos. Para aquellos que no están familiarizados, el cargador funciona usando un applet Flash para darme más control sobre el diálogo FileOpen. Puedo especificar un filtro para tipos de archivo, permitir que múltiples archivos para ser seleccionados, etc. Es muy bueno, pero tiene la siguiente limitación documentada:¿Puedo poner una ID de sesión de ASP.Net en un campo de formulario oculto?

Debido a un error de Flash conocido, la subida se ejecuta en Firefox en Windows hace no envíe las cookies correctas con la carga; en lugar de enviar cookies de Firefox, envía las cookies de Internet Explorer para el dominio respectivo. Como solución, sugerimos utilizar un método de carga sin cookies o anexar document.cookie a la solicitud de carga.

Por lo tanto, si un usuario usa Firefox, no puedo confiar en que las cookies persistan en su sesión cuando carguen un archivo. Necesito su sesión porque necesito saber quiénes son. Como solución, estoy usando el objeto de aplicación de esta manera:

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

Por lo tanto, estoy creando un identificador único y que sirva como una clave para almacenar el objeto Page.User en el ámbito de aplicación. Incluyo ese ID como una variable en el POST cuando se carga el archivo. Luego, en el controlador que acepta la carga de archivos, que agarrar el objeto de usuario de esta manera:

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

funciona de esta realidad, pero tiene dos inconvenientes evidentes:

  • Si IIS, el grupo de aplicación, o incluso si la aplicación se reinicia desde el momento en que el usuario visita la página de carga y realmente carga un archivo, su "uploadid" se elimina del alcance de la aplicación y la carga falla porque no puedo autenticarlos.

  • Si alguna vez escala a un escenario de granja de servidores web (posiblemente incluso un jardín web), esto se romperá por completo. Puede que no me preocupe, excepto que planeo escalar esta aplicación en el futuro.

¿Alguien tiene una manera mejor? ¿Hay alguna forma de que pase el ID de sesión de ASP.Net real en una variable POST, y luego use esa ID en el otro extremo para recuperar la sesión?

Sé que puedo obtener la ID de sesión a través del Session.SessionID, y sé cómo usar YUI para publicarlo en la página siguiente. Lo que no sé es cómo usar ese SessionID para tomar la sesión del servidor de estado.

Sí, estoy usando un servidor de estado para almacenar las sesiones, por lo que persisten las aplicaciones/reinicios de IIS, y funcionarán en un escenario de granja de servidores web.

Respuesta

3

Here es una publicación del mantenedor de SWFUpload que explica cómo cargar la sesión desde una ID almacenada en Request.Form. Me imagino que lo mismo funcionaría para el componente de Yahoo.

Tenga en cuenta los descargos de responsabilidad de seguridad en la parte inferior de la publicación.


Al incluir un archivo Global.asax y el siguiente código se puede anular la falta de sesión ID de cookie:

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

advertencia de seguridad: No se limite a copiar y pegue este código en su aplicación ASP.Net sin saber lo que está haciendo. Introduce problemas de seguridad y posibilidades de Cross-site Scripting.

+0

Esto es exactamente lo que estaba buscando. ¡Gracias! –

+7

Oye ... el enlace parece estar roto ... ¿puedes actualizar? – Mulki

+2

sí, necesitamos esto! por favor proporcione un nuevo enlace! – pilavdzice

0

El identificador de sesión de ASP.Net se almacena en Session.SessionID por lo que puede configurarlo en un campo oculto y luego publicarlo en la página siguiente.

Creo, sin embargo, que si la aplicación se reinicia, el sessionID caducará si no lo hace store your sessions in sql server.

1

Usted puede conseguir su actual SessionID desde el siguiente código:

string sessionId = HttpContext.Current.Session.SessionID; 

A continuación, se puede alimentar a que en un campo oculto tal vez y luego acceder a ese valor a través de YUI.

Es solo un logro, por lo que espero que no tenga ningún problema de escala. Sin embargo, hay problemas de seguridad que no sé.

1

Basándose en this blog post, aquí es una función que debe conseguir que la sesión para cualquier usuario en base a la identificación de la sesión, aunque no es bastante:

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

¡Perfecto! ¡Gracias! – defines

Cuestiones relacionadas