2008-09-04 3 views
9

Я использую загрузчик Yahoo, часть библиотеки пользовательского интерфейса Yahoo, на моем сайте ASP.Net, чтобы пользователи могли загружать файлы. Для незнакомых пользователей загрузчик работает с помощью апплета Flash, чтобы дать мне больше контроля над диалогом FileOpen. Я могу задать фильтр для типов файлов, позволяют несколько файлов, которые будут выбраны, и т.д. Это здорово, но она имеет следующий документированную ограничение:Могу ли я установить идентификатор сеанса ASP.Net в поле скрытой формы?

Из-за известной флэш-ошибка, то загрузчик работает в Firefox в Windows, делает не отправлять правильные файлы cookie с загрузкой; вместо отправки файлов cookie Firefox он отправляет файлы cookie в Internet Explorer для соответствующего домена. В качестве обходного пути мы предлагаем либо использовать метод загрузки cookieless, либо добавить document.cookie в запрос на загрузку.

Таким образом, если пользователь использует Firefox, я не могу полагаться на файлы cookie, чтобы сохранить их сессию при загрузке файла. Мне нужна их сессия, потому что мне нужно знать, кто они! В качестве обходного пути, я использую объект Application таким образом:

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

Итак, я создаю уникальный идентификатор и использовать его в качестве ключа для хранения Page.User объекта в рамках приложения. Я включаю этот ID как переменную в POST при загрузке файла. Затем в обработчике, который принимает загрузки файла, я захватить объект пользователя таким образом:

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

Это на самом деле работает, но она имеет две вопиющие недостатки:

  • Если IIS, приложение бассейн, или даже просто приложение перезапускается между моментом, когда пользователь посещает страницу загрузки, и фактически загружает файл, их «uploadid» удаляется из области приложения, и загрузка не выполняется, потому что я не могу их аутентифицировать.

  • Если я когда-либо масштабируюся до сценария веб-фермы (возможно, даже веб-сада), это полностью сломается. Я мог бы не волноваться, если не планировать масштабирование этого приложения в будущем.

У кого-нибудь есть лучший способ? Есть ли способ передать фактический идентификатор сеанса ASP.Net в переменной POST, а затем использовать этот идентификатор на другом конце для получения сеанса?

Я знаю, что могу получить идентификатор сеанса через Session.SessionID, и я знаю, как использовать YUI, чтобы опубликовать его на следующей странице. Я не знаю, как использовать этот SessionID для захвата сеанса с государственного сервера.

Да, я использую государственный сервер для хранения сеансов, поэтому они сохраняют перезапуск приложения/IIS и будут работать в сценарии веб-фермы.

ответ

3

Here - это сообщение от сопровождающего SWFUpload, в котором объясняется, как загрузить сеанс из идентификатора, хранящегося в Request.Form. Я предполагаю, что то же самое будет работать для компонента Yahoo.

Обратите внимание на отказ от ответственности в нижней части сообщения.


Включив файл Global.asax и следующий код, который вы можете переопределить недостающую Session ID печенье:

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

Предупреждение безопасности: Не просто скопировать и вставьте этот код в приложение ASP.Net, не зная, что вы делаете. Он представляет проблемы безопасности и возможности межсайтового скриптинга.

+0

Это именно то, что я искал. Благодаря! – 2008-10-27 15:58:41

+7

Эй ... ссылка, похоже, сломана. – Mulki 2010-10-28 07:00:24

0

Идентификатор сеанса ASP.Net хранится в Session.SessionID, поэтому вы можете установить это в скрытом поле, а затем отправить его на следующую страницу.

Я думаю, что если приложение перезагрузится, sessionID истечет, если вы не сделаете store your sessions in sql server.

1

Вы можете получить текущую SessionID из следующего кода:

string sessionId = HttpContext.Current.Session.SessionID; 

Затем вы можете кормить, что в скрытое поле, может быть, и затем получить доступ к этому значению через YUI.

Это просто получить, поэтому, надеюсь, у вас не будет проблем с масштабированием. Проблемы безопасности, хотя я этого не знаю.

1

Опираясь на this blog post, вот функция, вы должны получить сеанс для любого пользователя на основе идентификатора сеанса, хотя это не очень:

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; 
} 
Смежные вопросы