Как создать постоянный тикет в Redis - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть приложение Identity Server 4, которое я пытаюсь запомнить (сохранить) логин пользователя.

Я думаю, что отследил проблему до чего-то в Redis.

Когда билеты хранятся в Redis, они хранятся с тайм-аутом.

127.0.0.1:6379> ttl Ids-v2-Local-Key-74c112d5-e0f4-48c4-9d0f-cd8e62f12dfd
(integer) 3014

Пока приложение открыто, Redis будет обновлять тайм-аут.

1542808250.760394 [0 lua] "EXPIRE" "Ids-v2-Local-Key-74c112d5-e0f4-48c4-9d0f-cd8e62f12dfd" "3600"

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

Я смог исправить это, вручную войдя в Redis и установив ключ для Persist

127.0.0.1:6379> Persist XenaIdentityserver-v2-Local-Key-74c112d5-e0f4-48c4-9d0f-cd8e62f12dfd
(integer) 1
127.0.0.1:6379> ttl XenaIdentityserver-v2-Local-Key-74c112d5-e0f4-48c4-9d0f-cd8e62f12dfd
(integer) -1

Я думаю, проблема в том, как создаются ключи в Redis.

RedisCacheTicketStore

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Redis;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;

namespace Xena.IdentityServer.Services
{
    public class RedisCacheTicketStore : ITicketStore
    {
        private readonly ILogger _logger;
        private string KeyPrefix = "AuthSessionStore-";
        private IDistributedCache _cache;

        public RedisCacheTicketStore(RedisCacheOptions options, ILogger logger, IConfiguration config)
        {
            KeyPrefix = config["Redis:ApplicationName"] + "-";

            _logger = logger;
            _cache = new RedisCache(options);
        }

        public async Task<string> StoreAsync(AuthenticationTicket ticket)
        {
            var sw = new Stopwatch();
            sw.Start();

            var guid = Guid.NewGuid();
            var key = KeyPrefix + guid.ToString();
            await RenewAsync(key, ticket);

            _logger.LogDebug(LoggingEvents.RedisCacheTicketStore, "Redis Method StoreAsync Elapsed {sw.ElapsedMilliseconds}", sw.ElapsedMilliseconds);

            return key;
        }

        public Task RenewAsync(string key, AuthenticationTicket ticket)
        {
            var sw = new Stopwatch();
            sw.Start();

            var options = new DistributedCacheEntryOptions();
            var expiresUtc = ticket.Properties.ExpiresUtc;
            if (expiresUtc.HasValue)
            {
                options.SetAbsoluteExpiration(expiresUtc.Value);
            }

            options.SetSlidingExpiration(TimeSpan.FromMinutes(60));

            byte[] val = SerializeToBytes(ticket, _logger);
            _cache.Set(key, val, options);
            sw.Stop();
            _logger.LogDebug(LoggingEvents.RedisCacheTicketStore, "Redis Method RenewAsync Elapsed {sw.ElapsedMilliseconds}", sw.ElapsedMilliseconds);
            return Task.FromResult(0);
        }

        public Task<AuthenticationTicket> RetrieveAsync(string key)
        {
            var sw = new Stopwatch();
            sw.Start();

            AuthenticationTicket ticket;
            byte[] bytes = null;
            bytes = _cache.Get(key);
            ticket = DeserializeFromBytes(bytes, _logger);

            sw.Stop();
            _logger.LogDebug(LoggingEvents.RedisCacheTicketStore, "Redis Method RetrieveAsync Elapsed {sw.ElapsedMilliseconds}", sw.ElapsedMilliseconds);

            return Task.FromResult(ticket);
        }

        public Task RemoveAsync(string key)
        {
            var sw = new Stopwatch();
            sw.Start();

            _cache.Remove(key);

            sw.Stop();
            _logger.LogDebug(LoggingEvents.RedisCacheTicketStore, "Redis Method RemoveAsync Elapsed {sw.ElapsedMilliseconds}", sw.ElapsedMilliseconds);


            return Task.FromResult(0);
        }

        private static byte[] SerializeToBytes(AuthenticationTicket source, ILogger logger)
        {
            var sw = new Stopwatch();
            sw.Start();

            var ticket = TicketSerializer.Default.Serialize(source);

            sw.Stop();
            logger.LogDebug(LoggingEvents.RedisCacheTicketStore, "Redis Method SerializeToBytes Elapsed {sw.ElapsedMilliseconds}", sw.ElapsedMilliseconds);

            return ticket;
        }

        private static AuthenticationTicket DeserializeFromBytes(byte[] source, ILogger logger)
        {
            var sw = new Stopwatch();
            sw.Start();

            var hold = source == null ? null : TicketSerializer.Default.Deserialize(source);

            sw.Stop();
            logger.LogDebug(LoggingEvents.RedisCacheTicketStore, "Redis Method DeserializeFromBytes Elapsed {sw.ElapsedMilliseconds}", sw.ElapsedMilliseconds);

            return hold;
        }   

    }
}

Я могу перейти по коду и увидеть, что AuthenticationTicketустановите isPersistant при переходе через метод StoreAsync.Однако он не создает постоянный тикет, на котором все еще есть время ожидания.

enter image description here

Как мне сообщить _cache.Set (key, val, options);установить постоянный билет, а не один с тайм-аутом?

1 Ответ

0 голосов
/ 22 ноября 2018

После подсказки от Кирка Ларкина в комментарии.Мне пришло в голову, что все, что мне действительно нужно было сделать, это установить тайм-аут дольше, чем он будет продолжать скользить, пока пользователь активен.Если бы я установил его на Persist, то он был бы в redis навсегда, и это действительно не то, что мы хотим.Мы хотим, чтобы он был там в течение определенного периода времени, пока пользователь время от времени возвращается, и он продолжает отображаться для входа в систему.

public Task RenewAsync(string key, AuthenticationTicket ticket)
        {
            var options = new DistributedCacheEntryOptions();
            var expiresUtc = ticket.Properties.ExpiresUtc;
            if (expiresUtc.HasValue)
                options.SetAbsoluteExpiration(expiresUtc.Value);

            if (ticket.Properties.IsPersistent && !expiresUtc.HasValue)
                options.SetSlidingExpiration(_rememberMeTimeoutInDays);
            else if (ticket.Properties.IsPersistent && expiresUtc.HasValue)
                options.SetSlidingExpiration(TimeSpan.FromTicks(expiresUtc.Value.Ticks));
            else
                options.SetSlidingExpiration(_defaultTimeoutInHours);

            byte[] val = SerializeToBytes(ticket, _logger);
            _cache.Set(key, val, options);
            return Task.FromResult(0);
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...