2008-09-04 40 views
9

我在我的ASP.Net網站上使用雅虎上傳器,雅虎UI庫的一部分,以允許用戶上傳文件。對於那些不熟悉的人來說,上傳器使用Flash小程序工作,讓我更好地控制FileOpen對話框。我可以爲文件類型指定一個過濾器,允許選擇多個文件等等。它很棒,但它具有以下記錄的限制:我可以在一個隱藏的表單字段中放置一個ASP.Net會話ID嗎?

由於已知的Flash錯誤,在Windows中的Firefox中運行的Uploader會沒有發送正確的cookies與上傳;它不是發送Firefox cookies,而是發送Internet Explorer的Cookie用於相應的域。作爲解決方法,我們建議使用無Cookie的上傳方法或將document.cookie附加到上傳請求。

因此,如果用戶使用Firefox,當他們上傳文件時,我不能依靠Cookie來堅持他們的會話。我需要他們的會議,因爲我需要知道他們是誰!作爲一種變通方法,我使用的應用程序對象正是如此:

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

所以,我創建一個唯一的ID,並使用它作爲一個鍵存儲在應用程序範圍內Page.User對象。當文件上傳時,我將該ID作爲變量包含在POST中。然後,在接受文件的上傳處理程序中,我抓住用戶對象正是如此:

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

這實際工作,但它有兩個明顯的缺點:

  • 如果IIS,應用程序池,或者甚至只是在用戶訪問上載頁面之間重新啓動應用程序,並且實際上傳文件時,他們的「uploadid」將從應用程序範圍中刪除,並且上傳失敗,因爲我無法對其進行身份驗證。

  • 如果我擴展到一個網絡農場(甚至可能是一個網絡花園)的場景,這將徹底破壞。我可能不會擔心,除非我計劃在將來擴展此應用程序。

有沒有人有更好的方法?有沒有辦法讓我在POST變量中傳遞實際的ASP.Net會話ID,然後在另一端使用該ID來檢索會話?

我知道我可以通過Session.SessionID獲得會話ID,並且我知道如何使用YUI將其發佈到下一頁。我不知道的是如何使用SessionID從狀態服務器獲取會話。

是的,我使用狀態服務器來存儲會話,因此它們堅持應用程序/ IIS重新啓動,並且可以在Web場景中工作。

回答

3

Here是來自SWFUpload維護者的文章,它解釋瞭如何從存儲在Request.Form中的ID加載會話。我想象同樣的事情可以用於雅虎組件。

請注意帖子底部的安全免責聲明。


通過包括Global.asax文件和下面的代碼,您可以覆蓋缺少的會話ID的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); 
     } 
    } 
} 

安全警告:不要只是複製並將此代碼粘貼到您的ASP.Net應用程序中,而不知道您在做什麼。它介紹了跨站腳本的安全問題和可能性。

+0

這正是我一直在尋找。謝謝! – 2008-10-27 15:58:41

+7

嘿...鏈接似乎被打破..可以更新嗎? – Mulki 2010-10-28 07:00:24

0

ASP.Net會話ID存儲在Session.SessionID中,因此您可以將它設置在隱藏字段中,然後將其發佈到下一頁。

但是,我認爲,如果應用程序重新啓動,那麼sessionID將會過期,如果您不是store your sessions in sql server

1

您可以從下面的代碼中獲得當前的SessionID:

string sessionId = HttpContext.Current.Session.SessionID; 

然後你可以喂到這一個隱藏字段也許再經過YUI訪問該值。

這只是一個get,所以你希望不會有任何縮放問題。安全問題,但我不知道。

1

依託this blog post,這裏是應該讓您基於會話ID的任何用戶會話的功能,但它不漂亮:

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; 
} 
相關問題