ASP.NET sessionId + OWIN Cookies не отправляются в браузер
у меня есть странная проблема с использованием аутентификации OWIN cookie.
когда я запускаю свою аутентификацию сервера IIS, она отлично работает на IE / Firefox и Chrome.
Я начал делать некоторые тесты с проверкой подлинности и входа в систему на разных платформах, и я придумал странную ошибку. Спорадически Owin framework / IIS просто не отправляет куки-файлы в браузеры. Я введу имя пользователя и пароль, который является правильным код работает, но не куки доставляется в браузер вообще. Если я перезапущу сервер, он начнет работать, то в какой-то момент я попробую войти в систему, и снова куки перестанут доставляться. Переход через код ничего не делает и не выдает ошибок.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
CookieHttpOnly = true,
AuthenticationType = "ABC",
LoginPath = new PathString("/Account/Login"),
CookiePath = "/",
CookieName = "ABC",
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
if (!IsAjaxRequest(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
}
}
});
и в моей процедуре входа в систему у меня есть следующий код:
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var authentication = HttpContext.Current.GetOwinContext().Authentication;
var identity = new ClaimsIdentity("ABC");
identity.AddClaim(new Claim(ClaimTypes.Name, user.Username));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.User_ID.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Role, role.myRole.ToString()));
authentication.AuthenticationResponseGrant =
new AuthenticationResponseGrant(identity, new AuthenticationProperties()
{
IsPersistent = isPersistent
});
authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, identity);
обновление 1: кажется, что одна из причин проблемы заключается в том, что когда я добавляю элементы в сеанс, начинаются проблемы. Добавление чего-то простого, как Session.Content["ABC"]= 123 Кажется, чтобы создать проблему.
что я могу разобрать, так это следующее:
1) (Chrome) при входе в систему я получаю ASP.NET_SessionId + мой файл cookie аутентификации.
2) захожу на страницу, которая устанавливает сеанс.содержание...
3) откройте новый браузер (Firefox) и попробуйте войти в систему, и он не получает ASP. NET_SessionId и не получает файл Cookie аутентификации
4) в то время как первый браузер имеет ASP.NET_SessionId он продолжает работать. В ту минуту, когда я удаляю этот файл cookie, у него такая же проблема, как и у всех других броузеры
Я работаю над ip-адресом (10.x. x. x) и localhost.
обновление 2: сила творения ASPNET_SessionId сначала на моей странице login_load перед аутентификацией с OWIN.
1) Прежде чем я проверить подлинность долг я сделать случайную Session.Content значение на моей странице входа, чтобы запустить ASP. NET_SessionId
2) Затем я проверить подлинность и делать дальнейшие сеансы
3) другие браузеры, кажется, теперь работают
это странно. Я могу только заключить, что это имеет какое-то отношение с ASP и OWIN думают, что они находятся в разных областях или что-то в этом роде.
обновление 3 - странное поведение между двумя.
дополнительное странное поведение идентифицировано-тайм-аут сеанса Owin и ASP отличается. Я вижу, что мои сеансы Owin остаются живыми дольше, чем мои сеансы ASP через какой-то механизм. Поэтому при входе в:
1.) У меня есть cookied на основе auth сессии
2.) Я установил несколько переменных сеанса
мой переменные сеанса (2)" умирают " до того, как переменная сеанса cookie owin заставляет повторно войти в систему, что вызывает неожиданное поведение во всем моем приложении. (Человек вошел в систему, но на самом деле не вошел в систему)
обновление 3B
после некоторого копания я увидел некоторые комментарии на странице, которые говорят, что тайм-аут аутентификации "форм" и тайм-аут сеанса должны совпадать. Я думаю, что обычно они синхронизированы, но по какой-то причине их нет синхронизация.
резюме решений
1)всегда создавайте сеанс перед аутентификацией. В основном создать сеанс при запуске приложения Session["Workaround"] = 0;
2) [экспериментальный] если вы сохраняете куки, убедитесь, что ваш тайм-аут / длина OWIN больше, чем ваш sessionTimeout в вашем интернете.конфиг (в тестировании)
8 ответов:
я столкнулся с той же проблемой и проследил причину OWIN ASP.NET реализация хостинга. Я бы сказал, что это ошибка.
какой-то фон
мои выводы основаны на этих версиях сборки:
- Microsoft.Owin, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
- Microsoft.Долг.Хозяин.SystemWeb, Version=2.0.2.0, Culture=нейтральный, PublicKeyToken=31bf3856ad364e35
это работает и оба куки правильно отправляются в браузер...public ActionResult Index() { HttpContext.GetOwinContext() .Response.Cookies.Append("OwinCookie", "SomeValue"); HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue"; return View(); }но это не и овин-куки "потерялся"...
public ActionResult Index() { HttpContext.GetOwinContext() .Response.Cookies.Append("OwinCookie", "SomeValue"); HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue"; HttpContext.Response.Cookies.Remove("ASPCookie"); return View(); }оба протестированы из VS2013, iisexpress и шаблона проекта MVC по умолчанию.
начиная с большого анализа @TomasDolezal, я посмотрел как на Owin, так и на систему.Веб-источник.
проблема в том, что система.Web имеет свой собственный главный источник информации о cookie, и это не заголовок Set-Cookie. Owin знает только о заголовке Set-Cookie. Обходной путь заключается в том, чтобы убедиться, что любые куки, установленные Owin, также установлены в
HttpContext.Current.Response.Cookiesколлекция.Я сделал небольшое промежуточное ПО (источник, nuget), что делает именно то, что предназначено для размещения непосредственно над регистрацией промежуточного программного обеспечения cookie.
app.UseKentorOwinCookieSaver(); app.UseCookieAuthentication(new CookieAuthenticationOptions());
короче, менеджер файлов cookie .NET выиграет над менеджером файлов cookie OWIN и перезапишет файлы cookie, установленные на слое OWIN. Исправление заключается в использовании класс SystemWebCookieManager, предоставленный в качестве решения для проекта Katana здесь. Вам нужно использовать этот класс или один похожий на него, который будет заставить OWIN использовать диспетчер файлов cookie .NET, чтобы не было несоответствий:
public class SystemWebCookieManager : ICookieManager { public string GetRequestCookie(IOwinContext context, string key) { if (context == null) { throw new ArgumentNullException("context"); } var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName); var cookie = webContext.Request.Cookies[key]; return cookie == null ? null : cookie.Value; } public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options) { if (context == null) { throw new ArgumentNullException("context"); } if (options == null) { throw new ArgumentNullException("options"); } var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName); bool domainHasValue = !string.IsNullOrEmpty(options.Domain); bool pathHasValue = !string.IsNullOrEmpty(options.Path); bool expiresHasValue = options.Expires.HasValue; var cookie = new HttpCookie(key, value); if (domainHasValue) { cookie.Domain = options.Domain; } if (pathHasValue) { cookie.Path = options.Path; } if (expiresHasValue) { cookie.Expires = options.Expires.Value; } if (options.Secure) { cookie.Secure = true; } if (options.HttpOnly) { cookie.HttpOnly = true; } webContext.Response.AppendCookie(cookie); } public void DeleteCookie(IOwinContext context, string key, CookieOptions options) { if (context == null) { throw new ArgumentNullException("context"); } if (options == null) { throw new ArgumentNullException("options"); } AppendResponseCookie( context, key, string.Empty, new CookieOptions { Path = options.Path, Domain = options.Domain, Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), }); } }при запуске приложения просто назначьте его, когда вы создание зависимостей долг:
app.UseCookieAuthentication(new CookieAuthenticationOptions { ... CookieManager = new SystemWebCookieManager() ... });аналогичный ответ был предоставлен здесь, но он не включает всю кодовую базу, необходимую для решения проблемы, поэтому я вижу необходимость добавить ее здесь, потому что внешняя ссылка на проект Katana может снизиться, и это должно быть полностью записано как решение здесь.
команда Катана ответила на вопрос Томас Долезар поднял, и отправил документация о обходных путях:
обходные пути делятся на две категории. Один из них-переконфигурировать Система.Веб, поэтому он избегает использования ответа.Коллекция печенья и перезапись печенья OWIN. Другой подход заключается в повторной настройке затронутые компоненты OWIN, поэтому они пишут файлы cookie непосредственно Система.Ответ веба.Коллекция печенья.
- убедитесь, что сеанс установлен до аутентификации: конфликт между системой.Веб и Катана куки-файлы по запросу, так что это может быть возможно для приложения установить сеанс по некоторому запросу до прохождения проверки подлинности. Это должно быть легко сделать, когда пользователь сначала прибывает, но это может быть сложнее гарантировать позже, когда сеансовые или аутентификационные куки истекают и / или должны быть обновлены.
- отключить SessionStateModule-если приложение не полагается на информацию о сеансе, но модуль сеанса все еще устанавливает cookie, который вызывает вышеуказанный конфликт, тогда вы можете рассмотреть возможность отключения модуль состояния сеанса.
- перенастроить CookieAuthenticationMiddleware для записи непосредственно в систему.Коллекция веб-файлов cookie.
app.UseCookieAuthentication(new CookieAuthenticationOptions { // ... CookieManager = new SystemWebCookieManager() });смотрите реализацию SystemWebCookieManager из документации (ссылка выше)
больше информации здесь
Edit
ниже шаги, которые мы сделали, чтобы решить эту проблему. Как 1. и 2. решил проблему также отдельно, но мы решили применить оба на всякий случай:
1. Используйте SystemWebCookieManager
2. Установите переменную сеанса:
protected override void Initialize(RequestContext requestContext) { base.Initialize(requestContext); // See http://stackoverflow.com/questions/20737578/asp-net-sessionid-owin-cookies-do-not-send-to-browser/ requestContext.HttpContext.Session["FixEternalRedirectLoop"] = 1; }(Примечание стороны: метод инициализации выше является логическим местом для исправления, потому что база.Инициализация делает сеанс доступным. Однако исправление может также OpenID будет применяться позже, потому что в OpenId есть сначала анонимный запрос, а затем перенаправление к поставщику OpenId, а затем обратно в приложение. Проблемы будут возникать после перенаправления обратно в приложение, в то время как исправление устанавливает переменную сеанса уже во время первого анонимного запроса, тем самым устраняя проблему до того, как произойдет перенаправление назад)
Edit 2
копировать-вставить проект Катана 2016-05-14:
добавить это:
app.UseCookieAuthentication(new CookieAuthenticationOptions { // ... CookieManager = new SystemWebCookieManager() });...а это:
public class SystemWebCookieManager : ICookieManager { public string GetRequestCookie(IOwinContext context, string key) { if (context == null) { throw new ArgumentNullException("context"); } var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName); var cookie = webContext.Request.Cookies[key]; return cookie == null ? null : cookie.Value; } public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options) { if (context == null) { throw new ArgumentNullException("context"); } if (options == null) { throw new ArgumentNullException("options"); } var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName); bool domainHasValue = !string.IsNullOrEmpty(options.Domain); bool pathHasValue = !string.IsNullOrEmpty(options.Path); bool expiresHasValue = options.Expires.HasValue; var cookie = new HttpCookie(key, value); if (domainHasValue) { cookie.Domain = options.Domain; } if (pathHasValue) { cookie.Path = options.Path; } if (expiresHasValue) { cookie.Expires = options.Expires.Value; } if (options.Secure) { cookie.Secure = true; } if (options.HttpOnly) { cookie.HttpOnly = true; } webContext.Response.AppendCookie(cookie); } public void DeleteCookie(IOwinContext context, string key, CookieOptions options) { if (context == null) { throw new ArgumentNullException("context"); } if (options == null) { throw new ArgumentNullException("options"); } AppendResponseCookie( context, key, string.Empty, new CookieOptions { Path = options.Path, Domain = options.Domain, Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), }); } }
ответы уже были предоставлены, но в owin 3.1.0 есть класс SystemWebChunkingCookieManager, который можно использовать.
app.UseCookieAuthentication(new CookieAuthenticationOptions { ... CookieManager = new SystemWebChunkingCookieManager() ... });
если вы устанавливаете куки в OWIN middleware самостоятельно, то с помощью
OnSendingHeadersКажется, чтобы обойти эту проблему.например, используя код ниже
owinResponseCookie2будет установлен, даже еслиowinResponseCookie1нет:private void SetCookies() { var owinContext = HttpContext.GetOwinContext(); var owinResponse = owinContext.Response; owinResponse.Cookies.Append("owinResponseCookie1", "value1"); owinResponse.OnSendingHeaders(state => { owinResponse.Cookies.Append("owinResponseCookie2", "value2"); }, null); var httpResponse = HttpContext.Response; httpResponse.Cookies.Remove("httpResponseCookie1"); }
самое быстрое однострочное кодовое решение:
HttpContext.Current.Session["RunSession"] = "1";просто добавьте эту строку перед CreateIdentity метод:
HttpContext.Current.Session["RunSession"] = "1"; var userIdentity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie); _authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = rememberLogin }, userIdentity);
у меня был тот же симптом заголовка Set-Cookie, который не был отправлен, но ни один из этих ответов не помог мне. Все работало на моей локальной машине, но при развертывании в производство заголовки set-cookie никогда не будут установлены.
оказывается, это была комбинация с использованием пользовательского
CookieAuthenticationMiddlewareс WebApi вместе с поддержка сжатия WebApiк счастью, я использовал ELMAH в своем проекте, который позволил мне регистрировать это исключение:
Comments