IsPersistent не работает - файл cookie действителен только для текущего сеанса

У меня есть приложение ASP.NET MVC 5, использующее ASP.NET Identity 2.1.0 для аутентификации пользователей.
Раньше все работало нормально, но теперь я обнаружил, что постоянные сеансы пользователей больше не работают. Я не могу сказать, какое изменение сломало это, но это сработало, когда я реализовал Identity (конвертировал приложение из SimpleMembership), и это моя логика, которая у меня есть на данный момент:

var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, 
                                     model.RememberMe, shouldLockout: true);

SignInManager — это мой ApplicationSignInManager, основанный на SignInManager<ApplicationUser, int>, а model.RememberMe — это true.

И моя установка:

app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = ApplicationCookieIdentityValidator.OnValidateIdentity(
                    validateInterval: TimeSpan.FromMinutes(0),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
    });
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

Все работает нормально, кроме сохранения пользовательских сессий. Я проверил файлы cookie, возвращаемые моим сервером, и .AspNet.ApplicationCookie всегда возвращается как «действительный для текущего сеанса», а не какая-то дата в будущем. Поэтому, когда я закрываю и снова открываю браузер, мне нужно снова войти в систему...

Кто-нибудь знает, почему это не работает (больше)?

P.S.: Я переопределил SignInAsync в своем ApplicationSignInManager, потому что я делаю там некоторую пользовательскую логику, но я даже проверил с помощью отладчика и для следующего вызова:

await base.SignInAsync(user, isPersistent, rememberBrowser);

isPersistent равно true, поэтому он должен создать постоянный файл cookie.


person Christoph Fink    schedule 08.09.2014    source источник
comment
Я подозреваю, что validateInterval: TimeSpan.FromMinutes(0) может быть причиной этого. Потому что при каждом запросе он регенерирует куки и устанавливает новый. Попробуйте установить validateInterval на что-то большее, чем 0, и посмотрите, сработает ли это.   -  person trailmax    schedule 09.09.2014
comment
@trailmax: Спасибо, это все. Это изменилось с V 2.1? Потому что это определенно работало в начале (с V 2.0). В любом случае: опубликуйте это как ответ, и я приму его. Теперь мне нужно разобраться с этим, так как мне нужна (из-за единого входа) проверка для каждого запроса.   -  person Christoph Fink    schedule 09.09.2014


Ответы (3)


Это известная ошибка в Identity и, посмотрев на этот ответ не очень новый.

Когда файл cookie создается повторно при каждом запросе, флаг «IsPersisted» не устанавливается, даже если он был установлен в исходном файле cookie.

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

Я думаю, что у меня есть решение для вас, но я не компилировал и не тестировал его - просто общее направление того, куда вам нужно идти. Полный код см. в этом .
Это всего лишь SecurityStampValidator код, взятый из декомпилятора. Я добавил строки 91–96. В основном я беру флаг «IsPersistent» из предыдущего файла cookie и добавляю его в новый файл cookie при его создании. Этого не было сделано в немодифицированной версии.

И затем в вашем Auth.Config вы делаете:

Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = MySecurityStampValidator.OnValidateIdentity(
                    validateInterval: TimeSpan.FromMinutes(0),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }

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

person trailmax    schedule 08.09.2014
comment
Большое тебе спасибо. Поскольку у меня уже есть собственный валидатор (см. ApplicationCookieIdentityValidator в моем коде), мне просто нужно было добавить туда и ваши изменения -› работает! - person Christoph Fink; 09.09.2014
comment
@ChrFin Да, я заметил, что имя отличается от стандартного. Рад, что это помогает! - person trailmax; 09.09.2014
comment
хороший код! Похоже, что отсутствует using Microsoft.Owin.Security; для доступа к типу AuthenticationProperties. - person Matthew; 11.12.2015
comment
Это работает для меня stackoverflow.com/questions/31946582/ - person Balaji Gunasekaran; 10.10.2017
comment
@Сергей год? больше похоже на 4 года с момента моего ответа. Identity 2 больше не разрабатывается, чего вы ожидаете? - person trailmax; 24.04.2018

Обновление AspNet.Identity.Core и AspNet.Identity.Owin до версии 2.2.1 должно решить эту проблему.

person Mr. Flibble    schedule 25.09.2016
comment
после обновления у него все еще есть та же проблема, и даже шаблон по умолчанию для asp.mvc для ядра Identity имеет ту же проблему. - person Shahzad; 19.07.2017
comment
stackoverflow.com /вопросы/31946582/ - person Balaji Gunasekaran; 10.10.2017

Чтобы пользователь не вошел в систему в браузере, закройте Mvc Indentity. Приведенный ниже код — это то, что сработало для меня в классе Startup.Auth.cs.

app.UseCookieAuthentication(new CookieAuthenticationOptions
                    { 
                        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                        SlidingExpiration = true,
                        CookieHttpOnly = false,
                        LoginPath = new PathString("/Account/Login"),

                        Provider = new CookieAuthenticationProvider
                        {  
                            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                            validateInterval: TimeSpan.FromMinutes(30),

                                regenerateIdentity: (manager, user) => 
                                user.GenerateUserIdentityAsync(manager)),

                            OnResponseSignIn = context => {
                                context.Properties.IsPersistent = true; };
                            } 
        }
person Kainat Jan    schedule 27.03.2019
comment
К вашему сведению, вы не должны использовать здесь CookieHttpOnly = false. Он должен быть установлен в значение true или опущен (поскольку true используется по умолчанию). Файл cookie только для HTTP не может быть доступен с помощью JavaScript в браузере. Но с этим кодом вредоносный JavaScript из атаки межсайтового скриптинга может выдернуть файл cookie аутентификации вашего пользователя. - person John; 23.03.2021