Кэширование заявлений на стороне сервера с помощью Owin Authentication

У меня есть приложение, которое раньше использовало FormsAuthentication, и некоторое время назад я переключил его на использование IdentityModel с WindowsIdentityFramework, чтобы получить выгоду от аутентификации на основе утверждений, но это было довольно некрасиво в использовании и реализации. Итак, теперь я смотрю на OwinAuthentication.

Я смотрю на OwinAuthentication и Asp.Net Identity фреймворк. Но единственная реализация Asp.Net Identity фреймворка на данный момент использует EntityModel, а я использую nHibernate. Так что пока я хочу попробовать обойти Asp.Net Identity и просто использовать Owin Authentication напрямую. Наконец-то я смог получить рабочий логин, используя советы от "Как мне игнорировать магию Identity Framework и просто использовать промежуточное ПО OWIN auth для получения искомых утверждений?", но теперь мой файл cookie содержит претензии довольно большие. Когда я использовал IdentityModel, я смог использовать механизм кэширования на стороне сервера, который кэшировал утверждения на сервере, а файл cookie просто содержал простой токен для кэшированной информации. Есть ли аналогичная функция в OwinAuthentication, или мне придется реализовать ее самостоятельно?

Я думаю, что буду в одной из этих лодок ...

  1. Размер файла cookie составляет 3 КБ, да ладно, он немного великоват.
  2. Включите функцию, аналогичную IdentityModel SessionCaching в Owin, о которой я не знаю.
  3. Напишите мою собственную реализацию для кеширования информации, вызывающей раздувание cookie, и посмотрите, смогу ли я подключить его, когда я настраиваю Owin при запуске приложения.
  4. Я все делаю неправильно, и есть подход, о котором я не придумал, или я что-то неправильно использую в Owin.

    public class OwinConfiguration
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "Application",
                AuthenticationMode = AuthenticationMode.Active,
                CookieHttpOnly = true,
                CookieName = "Application",
                ExpireTimeSpan = TimeSpan.FromMinutes(30),
                LoginPath = "/Login",
                LogoutPath = "/Logout",
                ReturnUrlParameter="ReturnUrl",
                SlidingExpiration = true,
                Provider = new CookieAuthenticationProvider()
                {
                    OnValidateIdentity = async context =>
                    {
                        //handle custom caching here??
                    }
                }
                //CookieName = CookieAuthenticationDefaults.CookiePrefix + ExternalAuthentication.ExternalCookieName,
                //ExpireTimeSpan = TimeSpan.FromMinutes(5),
            });
        }
    }
    

ОБНОВЛЕНИЕ Я смог получить желаемый эффект, используя информацию, предоставленную Хонье, и придумал следующую логику ...

Provider = new CookieAuthenticationProvider()
{
    OnValidateIdentity = async context =>
    {
        var userId = context.Identity.GetUserId(); //Just a simple extension method to get the ID using identity.FindFirst(x => x.Type == ClaimTypes.NameIdentifier) and account for possible NULLs
        if (userId == null) return;
        var cacheKey = "MyApplication_Claim_Roles_" + userId.ToString();
        var cachedClaims = System.Web.HttpContext.Current.Cache[cacheKey] as IEnumerable<Claim>;
        if (cachedClaims == null)
        {
            var securityService = DependencyResolver.Current.GetService<ISecurityService>(); //My own service to get the user's roles from the database
            cachedClaims = securityService.GetRoles(context.Identity.Name).Select(role => new Claim(ClaimTypes.Role, role.RoleName));
            System.Web.HttpContext.Current.Cache[cacheKey] = cachedClaims;
        }
        context.Identity.AddClaims(cachedClaims);
    }
}

person Nick Albrecht    schedule 04.10.2013    source источник
comment
Почему бы вам не использовать индивидуальную реализацию ASP.NET Identity? В NuGet уже есть реализации.   -  person Caleb Kiage    schedule 04.12.2013
comment
В то время, когда я занимался этим, их не было, о каких вы имеете в виду?   -  person Nick Albrecht    schedule 06.12.2013
comment
Nhibernate.AspNet.Identity, а также AspNet.Identity.NHibernate (я создал это с помощью SharpArchitecture и FluentNHibernate. Это предварительная версия)   -  person Caleb Kiage    schedule 07.12.2013
comment
В объекте CookieAuthenticationOptions есть поле под названием SessionStore, которое описывается как необязательный контейнер, в котором хранится идентификация между запросами. При использовании клиенту отправляется только идентификатор сеанса. Это можно использовать для смягчения потенциальных проблем с очень большими идентификаторами. Это похоже на то, что вы пытаетесь сделать. К сожалению, я не смог найти никаких ссылок о том, как на самом деле создать один из этих SessionStores.   -  person ThisGuy    schedule 20.12.2014
comment
Претензия - System.Security.Claims.Claim? Код для расширения GetUserId?   -  person Kiquenet    schedule 20.05.2016


Ответы (3)


Промежуточное ПО для аутентификации файлов cookie OWIN еще не поддерживает функцию кэширования сеансов. №2 - это не вариант.

# 3 - правильный путь. Как предложил Прабу, вы должны сделать в своем коде следующее:

OnResponseSignIn:

  • Сохранить context.Identity в кеше с уникальным ключом (GUID)
  • Создайте новый ClaimsIdentity, встроенный с уникальным ключом
  • Замените context.Identity новым идентификатором

OnValidateIdentity:

  • Получите уникальное утверждение ключа из context.Identity
  • Получите кешированную личность по уникальному ключу
  • Вызов context.ReplaceIdentity кэшированным идентификатором

Я собирался предложить вам сжать файл cookie, но обнаружил, что OWIN уже сделал это в своем TicketSerializer. Не вариант для тебя.

person Hongye Sun    schedule 07.10.2013
comment
Утверждения, которые приводят к увеличению размера файла cookie в моем случае, - это роли, используемые для разрешений на всем сайте. Есть ли причина, по которой мне следует кэшировать и заменять удостоверение целиком, или я могу оставить удостоверение нетронутым и просто кэшировать и добавить недостающие утверждения ClaimTypes.Role в задачу OnValidateIdentity? - person Nick Albrecht; 07.10.2013
comment
Конечно. Вы определенно можете настроить код в соответствии с требованиями вашего приложения. Я опубликовал общий способ ссылки на cookie из кеша сервера. - person Hongye Sun; 07.10.2013
comment
полный пример исходного кода для Create a new ClaimsIdentity embedded with the unique key и Replace context.Identity with the new identity? - person Kiquenet; 20.05.2016

Вы можете реализовать IAuthenticationSessionStore для хранения файлов cookie в базе данных.

Вот пример хранения cookie в Redis.

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
SessionStore = new RedisSessionStore(new TicketDataFormat(dataProtector)),
LoginPath = new PathString("/Auth/LogOn"),
LogoutPath = new PathString("/Auth/LogOut"),

});

Ознакомьтесь с полным примером здесь

person Alex Nguyen    schedule 03.08.2016
comment
если cookie аутентификации будет сохранен в базе данных, то что будет храниться на стороне клиента? - person Monojit Sarkar; 22.09.2016
comment
на стороне клиента хранится только идентификатор сеанса - person Alex Nguyen; 23.09.2016

person    schedule
comment
Я уже знал об этом разделе кода, и его копирование / вставка не отвечает на мой вопрос. - person Nick Albrecht; 07.10.2013
comment
Посмотрите событие OnResponseSignIn, которое я показал выше, и комментарий с ним. OnValidateIdentity, как я уже упоминал, вызывается для каждого запроса. По сути, есть 2 пункта: OnResponseSignIn создает сопоставление, OnValidateIdentity - ищет утверждения. - person Praburaj; 07.10.2013