Можно ли поместить идентификатор сеанса ASP.Net в скрытое поле формы? - PullRequest
9 голосов
/ 04 сентября 2008

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

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

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

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

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

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

Это на самом деле работает, но у него есть два явных недостатка:

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

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

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

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

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

Ответы [ 4 ]

4 голосов
/ 26 октября 2008

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

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


Включив файл Global.asax и следующий код, вы можете переопределить отсутствующий файл 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 голос
/ 10 сентября 2014

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

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;
}
1 голос
/ 04 сентября 2008

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

string sessionId = HttpContext.Current.Session.SessionID;

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

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

0 голосов
/ 04 сентября 2008

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

Я думаю, однако, что если приложение перезапустится, sessionID истечет, если вы не сохраните свои сессии на сервере sql .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...