我可以在隐藏的表单字段中放置ASP.Net会话ID吗?

时间:2008-09-04 08:08:40

标签: c# asp.net session yui

我在ASP.Net网站上使用Yahoo Uploader作为Yahoo UI Library的一部分,允许用户上传文件。对于那些不熟悉的人,上传者通过使用Flash小程序来帮助我更好地控制FileOpen对话框。我可以为文件类型指定过滤器,允许选择多个文件等。这很好,但它有以下记录的限制:

  

由于已知的Flash错误,Windows中的Firefox中运行的上传器不会通过上传发送正确的Cookie;它不是发送Firefox cookie,而是为相应的域发送Internet Explorer的cookie。作为解决方法,我们建议使用无Cookie上传方法或将document.cookie附加到上传请求。

因此,如果用户使用的是Firefox,我在上传文件时不能依赖Cookie来保持会话。我需要他们的会议,因为我需要知道他们是谁!作为一种解决方法,我正在使用Application对象:

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

因此,我正在创建一个唯一的ID,并将其用作在应用程序范围内存储Page.User对象的键。上传文件时,我将该ID作为POST中的变量包含在内。然后,在接受文件上传的处理程序中,我抓住User对象:

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

这实际上有效,但它有两个明显的缺点:

  • 如果IIS,应用程序池,甚至只是应用程序在用户访问上载页面和实际上载文件之间重新启动,则会从应用程序范围中删除它们的“uploadid”,并且上载失败,因为我无法对它们进行身份验证。

  • 如果我扩展到Web场(可能甚至是Web园)场景,这将完全破坏。我可能不会担心,除非我计划将来扩展这个应用程序。

有没有人有更好的方法?有没有办法让我在POST变量中传递实际的ASP.Net会话ID,然后在另一端使用该ID来检索会话?

我知道我可以通过Session.SessionID获取会话ID,我知道如何使用YUI将其发布到下一页。我不知道的是如何使用SessionID从状态服务器获取会话。

是的,我正在使用状态服务器来存储会话,因此它们会保持应用程序/ IIS重新启动,并且可以在Web场方案中运行。

4 个答案:

答案 0 :(得分:4)

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应用程序中,而不知道自己在做什么。它介绍了跨站点脚本的安全问题和可能性。

答案 1 :(得分:1)

您可以从以下代码中获取当前的SessionID:

string sessionId = HttpContext.Current.Session.SessionID;

然后您可以将其提供给隐藏字段,然后通过YUI访问该值。

这只是一个获得,所以你希望不会有任何扩展问题。但安全问题,我不知道。

答案 2 :(得分: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;
}

答案 3 :(得分:0)

ASP.Net会话ID存储在Session.SessionID中,因此您可以在隐藏字段中设置它,然后将其发布到下一页。

但是,我认为,如果应用程序重新启动,则如果您不store your sessions in sql server,则sessionID将过期。