JwtSecurityToken не истекает, когда он должен

В настоящее время я использую класс JwtSecurityToken в пространстве имен System.IdentityModels.Tokens. Я создаю токен, используя следующее:

DateTime expires = DateTime.UtcNow.AddSeconds(10);
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var genericIdentity = new System.Security.Principal.GenericIdentity(username, "TokenAuth");

ClaimsIdentity identity = new ClaimsIdentity(claims);
string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
var securityKey = new     InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
var signingCreds = new SigningCredentials(securityKey,     SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.HmacSha256Signature);
var securityToken = handler.CreateToken(
    issuer: issuer,
    audience: ConfigurationManager.AppSettings["UiUrl"].ToString(),
    signingCredentials: signingCreds,
    subject: identity,
    expires: expires,
    notBefore: DateTime.UtcNow
);
return handler.WriteToken(securityToken); 

По какой-то причине, несмотря на то, что срок истечения установлен на 10 секунд после текущего времени, он фактически не генерирует исключение, когда токен проверяется до примерно 5 минут. Увидев это, я подумал, что, возможно, было минимальное время истечения 5 минут, поэтому я установил время истечения срока:

DateTime.UtcNow.AddMinutes(5);

Затем он истекает через 10 минут, но в сообщении об исключении указано, что время истечения времени установлено на то, что оно должно быть (через 5 минут после входа пользователя в систему), и когда оно показывает текущее время в исключении, оно Через 5 минут после истечения срока. Таким образом, он, похоже, знает, когда он ДОЛЖЕН истечь, но на самом деле он не генерирует исключение только через 5 минут после истечения срока. Затем, поскольку токен, кажется, добавляет 5 минут в любое время, когда я установил его для истечения срока действия, я устанавливаю время истечения срока действия:

DateTime.UtcNow.AddMinutes(-5).AddSecond(10);

Я тестировал это, и до сих пор он еще не истек (спустя более десяти минут). Может кто-нибудь объяснить, почему это происходит и что я делаю неправильно? Кроме того, если вы видите что-либо еще с кодом, который я предоставил, любые рекомендации будут оценены, поскольку я новичок в использовании JWT и этой библиотеки.

Заранее благодарю

Ответ 1

Прочитав ответ @Denis Kucherov, я узнал, что могу использовать тот же пользовательский валидатор, который он опубликовал, не используя класс JwtBearerOptions, который потребовал бы, чтобы я добавил новую библиотеку.

Кроме того, поскольку существует два пространства имен, которые содержат много этих же классов, я обязательно упомянул, что все они используют пространства имен System.IdentityModels... namespaces. (НЕ Microsoft.IdentityModels...)

Ниже приведен код, который я использовал:

private bool CustomLifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken tokenToValidate, TokenValidationParameters @param)
{
    if (expires != null)
    {
        return expires > DateTime.UtcNow;
    }
    return false;
}
private JwtSecurityToken ValidateJwtToken(string tokenString)
{
   string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
   var securityKey = new InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
   JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
   TokenValidationParameters validation = new TokenValidationParameters()
   {
       ValidAudience = "MyAudience",
       ValidIssuer = "MyIssuer",
       ValidateIssuer = true,
       ValidateLifetime = true,
       LifetimeValidator = CustomLifetimeValidator,
       RequireExpirationTime = true,
       IssuerSigningKey = securityKey,
       ValidateIssuerSigningKey = true,
   };
   SecurityToken token;
   ClaimsPrincipal principal = handler.ValidateToken(tokenString, validation, out token);
   return (JwtSecurityToken)token;
}

Ответ 2

Проблема связана с ClockSkew. Обычно проверочные библиотеки (по крайней мере, одна из MS) компенсируют перекос тактовой частоты. ClockSkew значение по умолчанию составляет 5 минут. Смотрите ответ здесь

Вы можете изменить ClockSkew в TokenValidationParameters:

var tokenValidationParameters = new TokenValidationParameters
{
    //...your setting

    // set ClockSkew is zero
    ClockSkew = TimeSpan.Zero
};

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = tokenValidationParameters
});

Удачного кодирования!

Ответ 3

Кажется, что есть проблема с LifeTimeValidator. Вы можете просто переопределить свою логику с помощью специального делегата. Кроме того, используйте класс JwtBearerOptions для управления поведением промежуточного программного обеспечения. Например:

new JwtBearerOptions
        {
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
            TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                ValidIssuer = _configuration["Tokens:Issuer"],
                ValidAudience = _configuration["Tokens:Audience"],
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                LifetimeValidator = LifetimeValidator,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Tokens:Key"]))
            }
        }

И назначьте делегат LifetimeValidotor, чтобы предоставить свою собственную логику проверки таймаута:

private bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken token, TokenValidationParameters @params)
    {
        if (expires != null)
        {
            return expires > DateTime.UtcNow;
        }
        return false;
    }

Ответ 4

Я только что реализовал промежуточное программное обеспечение токена JWT, и, хотя в примерах в Интернете используется UtcNow, мне пришлось использовать Now или время истечения срока действия. Когда я использую Now, истекает время.

Ответ 5

Ниже ссылка даст вам точный ответ, так как по умолчанию время истечения MS составляет 5 минут. Так что либо вы должны сделать это на заказ, либо время, которое вы отдадите истекает: DateTime.Now.AddSeconds(30) 30 секунд в вышеуказанной строке будут добавлены в срок истечения. Таким образом, общее время истечения будет 5 минут и 30 секунд

https://github.com/IdentityServer/IdentityServer3/issues/1251

Надеюсь, это поможет.