Как узнать, когда истечет срок действия файла cookie OWIN?

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


person FrankO    schedule 15.04.2014    source источник
comment
Разве это невозможно?   -  person FrankO    schedule 20.04.2014


Ответы (2)


Все, что вам нужно, это получить CookieValidateIdentityContext на этапе проверки файлов cookie. Как только вы его получите, извлеките все, что вам нужно, и сохраните их как Claim или каким-либо другим способом, который вы предпочитаете.

Для MVC 5 с Asp.NET Identity 2.0 необходимо выполнить два шага:

  1. Определите пользовательский OnValidateIdentity, извлеките информацию о файлах cookie и сохраните ее как Claim.

    public class Startup
    {
      public void Configuration(IAppBuilder app)
      {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
          AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
          Provider = new CookieAuthenticationProvider
          {
            OnValidateIdentity = MyCustomValidateIdentity //refer to the implementation below
          }
        }
      }
    
    
      // this method will be called on every request
      // it is also one of the few places where you can access unencrypted cookie content as CookieValidateIdentityContext
      // once you get cookie information you need, keep it as one of the Claims
      // please ignore the MyUserManager and MyUser classes, they are only for sample, you should have yours
      private static Task MyCustomValidateIdentity(CookieValidateIdentityContext context)
      {
        // validate security stamp for 'sign out everywhere'
        // here I want to verify the security stamp in every 100 seconds.
        // but I choose not to regenerate the identity cookie, so I passed in NULL 
        var stampValidator = SecurityStampValidator.OnValidateIdentity<MyUserManager<Myuser>. MyUser>(TimeSpan.FromSeconds(100), null); 
        stampValidator.Invoke(context);
    
        // here we get the cookie expiry time
        var expireUtc = context.Properties.ExpiresUtc;
    
        // add the expiry time back to cookie as one of the claims, called 'myExpireUtc'
        // to ensure that the claim has latest value, we must keep only one claim
        // otherwise we will be having multiple claims with same type but different values
        var claimType = "myExpireUtc";
        var identity = context.Identity;
        if(identity.HasClaim(c=> c.Type == claimType))
        {
          var existingClaim = identity.FindFirst(claimType);
          identity.RemoveClaim(existingClaim); 
        }
        var newClaim = new Claim(claimType, expireUtc.Value.UtcTicks.ToString());
        context.Identity.AddClaim(newClaim);
    
        return Task.FromResult(0);
      }
    }
    
  2. Получите доступ к Claim в методах вашего контроллера

    // since expiry time has now become part of your claims, you now can get it back easily
    // this example just returns the remaining time in total seconds, as a string value
    // assuming this method is part of your controller methods
    
    public string RemainingTime()
    {
      var identity = User.Identity as ClaimsIdentity;
      var claimType = "myExpireUtc";  //NOTE: must be the same key value "myExpireUtc" defined in code shown above
    
      if(identity != null && identity.HasClaim(c=> c.Type == claimType))
      { 
        var expireOn = identity.FindFirstValue(claimType); 
    
        DateTimeOffset currentUtc = DateTimeOffset.UtcNow;
        DateTimeOffset? expireUtc = new DateTimeOffset(long.Parse(expireOn), TimeSpan.Zero);
    
        var remaining = (expireUtc.Value - currentUtc).TotalSeconds;
    
        return remaining.ToString();
      }
      return string.Empty;
    }
    

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

Кредит на этот пост Как мне получить доступ Значения AddClaims контекста Microsoft.Owin.Security.xyz OnAuthenticated?

person Phyo    schedule 25.06.2014
comment
У вас есть рабочий проект, в котором работает этот код? Пытаюсь понять, что делать с ar StampValidator = SecurityStampValidator.OnValidateIdentity‹MyUserManager‹Myuser›. MyUser›(TimeSpan.FromSeconds(100), ноль); поскольку у меня нет класса User Manager, а мой класс User - это просто DTO - person InTheWorldOfCodingApplications; 23.11.2016
comment
«Я использую этот подход, чтобы напомнить пользователям моего приложения о продлении сеанса до истечения времени сеанса». - как вы получаете время истечения срока действия, не продлевая его? Возможно, это связано с тем, что у вас включен скользящий срок действия? - person mlhDev; 17.11.2017
comment
Это действительно помогло мне. Но стоит заметить, что stampValidator.Invoke(context); ожидается и его следует ждать! Из-за этого у меня было неприятное исключение;) - person jgasiorowski; 07.05.2018
comment
Отличная идея, но для меня претензии никогда не сохраняются в моей реализации и недоступны в контроллере. Я должен использовать _userManager.AddClaim(user.Id, new Claim(i.ClaimTypeName, i.ClaimTypeValue)); для сохранения претензий. Поэтому я добавил статический список экземпляров класса, в которых хранятся значения, введенные для имени пользователя. Это, вероятно, не лучший способ работать на веб-ферме, но хранение зашифрованной записи в базе данных является вариантом. - person pixelda; 19.09.2018
comment
@phyo вы знаете, как продлить срок действия сеанса, когда он действительно истек? - person afr0; 05.08.2019
comment
@afr0 - я установил SlidingExpiration на true для CookieAuthenticationOptions. Это продлит срок действия файла cookie, когда пользователь делает новые HTTP-запросы во второй половине своего сеанса. Но если срок действия куки-файла аутентификации формы действительно истек, пользователь должен снова войти в систему. - person Phyo; 08.08.2019
comment
@Phyo согласен с этой частью, и SlidingExpiration также имеет значение true по умолчанию. form-authentication-cookie отличается от OWIN-Cookie? эти два должны использоваться вместе? - person afr0; 08.08.2019
comment
@Phyo, почему вы решили не восстанавливать файл cookie идентификации? В настоящее время у меня есть следующий код: regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync (manager, DefaultAuthenticationTypes.ApplicationCookie). Удаление этого (нулевого) повлияет? - person Cornel; 30.06.2021

Я просто хочу основываться на первом ответе, у меня были проблемы с его работой, поскольку я использовал пользовательское хранилище. хотя реализация мне кажется проще

public static class ApplicationCookieValidateIdentityContext
    {
        public static Task ApplicationValidateIdentity(CookieValidateIdentityContext context)
        {          
            var identity = context.Identity;

            if (identity.HasClaim(c => c.Type ==  "expires"))
            {
                var existingClaim = identity.FindFirst( "expires");
                identity.RemoveClaim(existingClaim);
            }

            if (context.Properties.ExpiresUtc == null) return Task.FromResult(0);

            context.Identity.AddClaim(new Claim("expires", context.Properties.ExpiresUtc.ToString()));

            return Task.FromResult(0);
        }
    }

Я также создал фильтр, который добавляет срок действия файла cookie.

// make sure its defaulted because the claim is not set on the login callback
var expires = DateTimeOffset.Now.AddMinutes(
    Convert.ToDouble(ConfigurationManager.AppSettings["SessionTimeInMinutes"]));


if (identity.HasClaim(c => c.Type == "expires"))
{
    expires = DateTimeOffset.Parse(identity.FindFirstValue("expires"));
}

cookieHeaderValues.Add(new SessionCookeHeaderValue("expiresAt", expires.ToString("O"), expires));

person Ricardo Saracino    schedule 25.10.2019
comment
У меня есть решение, которое учитывает SlidingExpiration stackoverflow.com/a/59038642/338456 - person Ricardo Saracino; 25.11.2019