ASP.NET: Session.SessionID изменяется между запросами

Почему свойство SessionID объекта- сеанса на странице ASP.NET изменяется между запросами?

У меня есть такая страница:

...
<div>
    SessionID: <%= SessionID %>
</div>
...

И вывод постоянно меняется каждый раз, когда я нажимаю F5, независимо от браузера.

13 ответов

Решение

Это причина

При использовании состояния сеанса на основе файлов cookie ASP.NET не выделяет хранилище для данных сеанса до тех пор, пока не будет использован объект Session. В результате новый идентификатор сеанса генерируется для каждого запроса страницы, пока не будет получен доступ к объекту сеанса. Если вашему приложению требуется статический идентификатор сеанса для всего сеанса, вы можете либо реализовать метод Session_Start в файле приложения Global.asax и сохранить данные в объекте Session для исправления идентификатора сеанса, либо использовать код в другой части вашего приложение для явного хранения данных в объекте Session.

http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.sessionid.aspx

Таким образом, в основном, если вы не обращаетесь к своему объекту сеанса на бэкэнде, новый sessionId будет генерироваться с каждым запросом

РЕДАКТИРОВАТЬ

Этот код необходимо добавить в файл Global.asax. Он добавляет запись в объект Session, поэтому вы фиксируете сеанс до его истечения.

protected void Session_Start(Object sender, EventArgs e) 
{
    Session["init"] = 0;
}

Есть еще одна, более коварная причина, почему это может происходить, даже если объект Session был инициализирован, как продемонстрировал Cladudio.

В файле Web.config, если есть <httpCookies> запись, которая установлена ​​в requireSSL="true" но вы на самом деле не используете HTTPS: для конкретного запроса куки-файл сеанса не отправляется (или, может быть, не возвращается, я не уверен, что), что означает, что вы получаете новый сеанс для каждого запроса.

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

В моем случае я выяснил, что cookie-файл сеанса имеет домен, который включает www. префикс, пока я запрашивал страницу без www.,
Добавление www. на URL сразу исправили проблему. Позже я изменил домен cookie, чтобы установить .mysite.com вместо www.mysite.com,

Моя проблема была в том, что у нас был этот набор в web.config

<httpCookies httpOnlyCookies="true" requireSSL="true" />

это означает, что при отладке в не-SSL (по умолчанию) файл cookie аутентификации не будет отправлен обратно на сервер. это будет означать, что сервер будет отправлять новый файл cookie авторизации (с новым сеансом) для каждого запроса обратно клиенту.

исправление заключается в том, чтобы либо установить для requiressl значение false в web.config и значение true в web.release.config, либо включить SSL во время отладки:

включить SSL

Используя ответ Невилла (удаляя requireSSL = true, в web.config) и немного модифицируя код Джоэла Эертона, вот код, который должен обрабатывать сайт, который работает как в режиме SSL, так и в режиме без SSL, в зависимости от пользователя и страницы (я Я возвращаюсь к коду и еще не тестировал его на SSL, но ожидаю, что он должен работать - позже он будет слишком занят, чтобы вернуться к этому, так что вот оно:

if (HttpContext.Current.Response.Cookies.Count > 0)
        {
            foreach (string s in HttpContext.Current.Response.Cookies.AllKeys)
            {
                if (s == FormsAuthentication.FormsCookieName || s.ToLower() == "asp.net_sessionid")
                {
                    HttpContext.Current.Response.Cookies[s].Secure = HttpContext.Current.Request.IsSecureConnection;
                }
            }
        }

В моем случае это было из-за того, что я изменял сессию после перенаправления со шлюза во внешнее приложение, и потому что я использовал IP вместо localhost в URL-адресе страницы, это фактически считалось другим веб-сайтом с разными сессиями.

В итоге

уделять больше внимания, если вы отлаживаете размещенное приложение на IIS вместо IIS Express и смешиваете свою машину http://ip/ и http://localhost/ на разных страницах

Другая возможность, которая заставляет SessionID меняться между запросами, даже когда Session_OnStart определен и / или Session был инициализирован, состоит в том, что имя хоста URL содержит недопустимый символ (такой как подчеркивание). Я считаю, что это специфично для IE (не проверено), но если ваш URL, скажем, http://server_name/appтогда IE заблокирует все куки и ваша информация о сеансе не будет доступна между запросами.

Фактически, каждый запрос запускает отдельный сеанс на сервере, поэтому, если ваша страница содержит несколько изображений, тегов сценария и т. Д., То каждый из этих запросов GET приведет к отдельному сеансу на сервере.

Дополнительная информация: http://support.microsoft.com/kb/316112

В моем случае это часто происходило в моей среде разработки и тестирования. После попытки всех вышеупомянутых решений без какого-либо успеха я обнаружил, что смог решить эту проблему, удалив все сеансовые куки. Расширение веб-разработчика делает это очень легко. В основном я использую Firefox для тестирования и разработки, но это также происходило во время тестирования в Chrome. Исправление также работало в Chrome.

Мне еще не приходилось делать это в производственной среде, и я не получал никаких сообщений о людях, которые не могут войти в систему. Это также, похоже, происходило только после того, как файлы cookie сеанса были безопасными. Это никогда не случалось в прошлом, когда они не были в безопасности.

Моя проблема была с приложением Microsoft MediaRoom IPTV. Оказывается, что MPF-приложения MPF не поддерживают файлы cookie; переход на использование сеансов без файлов cookie в web.config решил мою проблему

<sessionState cookieless="true"  />

Вот действительно старая статья об этом: Cookieless ASP.NET

Это менялось для меня, начиная с.NET 4.7.2, и это было связано со свойством SameSite в файле cookie сеанса. См. Здесь для получения дополнительной информации: https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/

Значение по умолчанию изменилось на "Lax" и начало ломаться. Я изменил его на "Нет", и все заработало, как ожидалось.

Я столкнулся с этой проблемой по-другому. Контроллеры, которые имели этот атрибут [SessionState(SessionStateBehavior.ReadOnly)] читали из другого сеанса, хотя я установил значение в исходном сеансе при запуске приложения. Я добавлял значение сеанса через _layout.cshtml (может быть, не самая лучшая идея?)

Очевидно, что эта проблема была вызвана ReadOnly, потому что когда я удалял атрибут, исходный сеанс (и SessionId) оставался в такте. Использование решения Клаудио /Microsoft исправило это.

Убедитесь, что у вас нет очень короткого времени ожидания сеанса, а также убедитесь, что, если вы используете сеансы на основе файлов cookie, вы принимаете сеанс.

FireFox webDeveloperToolbar полезен в такие моменты, когда вы можете увидеть файлы cookie, установленные для вашего приложения.

Я на.NET Core 2.1, и я хорошо знаю, что вопрос не в Core. Тем не менее, Интернета не хватает, и Google привел меня сюда, так надеясь сэкономить кому-то несколько часов.


Startup.cs

services.AddCors(o => o.AddPolicy("AllowAll", builder =>
            {
                builder
                    .WithOrigins("http://localhost:3000")     // important
                    .AllowCredentials()                       // important
                    .AllowAnyMethod()
                    .AllowAnyHeader();       // obviously just for testing
            }));

client.js

const resp = await fetch("https://localhost:5001/api/user", {
            method: 'POST',
            credentials: 'include',                           // important
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)
        })

Controllers/LoginController.cs

namespace WebServer.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        [HttpPost]
        public IEnumerable<string> Post([FromBody]LoginForm lf)
        {
            string prevUsername = HttpContext.Session.GetString("username");
            Console.WriteLine("Previous username: " + prevUsername);

            HttpContext.Session.SetString("username", lf.username);

            return new string[] { lf.username, lf.password };
        }
    }
}

Обратите внимание, что запись и чтение сеанса работает, но файлы cookie, похоже, не передаются в браузер. По крайней мере, я нигде не мог найти заголовок "Set-Cookie".

Сброс идентификатора сеанса может иметь много причин. Однако все вышеперечисленное не относится к моей проблеме. Поэтому я опишу это для дальнейшего использования.

В моем случае новый сеанс, созданный для каждого запроса, приводил к бесконечному циклу перенаправления. Действие перенаправления происходит в событии OnActionExecuting.

Также я очистил все заголовки http (также в событии OnActionExecuting с использованием метода Response.ClearHeaders), чтобы предотвратить кэширование сайтов на стороне клиента. Но этот метод очищает все заголовки, включая информацию о сеансе пользователя, и, следовательно, все данные во временном хранилище (которое я использовал позже в программе). Так что даже установка нового сеанса в событии Session_Start не помогла.

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

Надеюсь, это поможет кому-то.

Другие вопросы по тегам