В настоящее время я программирую ASP.NET-Core WebApi, используя JWT-Bearer-Authentication.
Чтобы сделать API доступным из разных часовых поясов, я использую следующий шаблон для установки полей nbf (notBefore) и exp (срок действия) внутри моего JWT в UTC-Timestamp:
var utcNow = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
...
var tokenOptions = new JwtSecurityToken(
notBefore: utcNow,
expires: utcNow.AddSeconds(3600),
);
...
Для генерации токенов все работает довольно хорошо, nbf и exp содержат метку времени UNIX, представляющую текущее время UTC.
Но при проверке токена все работает в течение 5 минут (моя настройка смещения часов), а затем я получаю только 401 от API, потому что проверка токена выполняется с моим текущим часовым поясом здесь, в Германии.
Есть ли способ настроить JwtAuthentication-Middleware в .NET-Core для использования UTC-Time для проверки токена? Или есть другие способы решить эту проблему?





Одним из решений является проверка токена без истечения срока действия. Это вернет действительный токен, даже если срок действия токена истек. Затем в своем коде вручную проверьте время истечения срока действия токенов. Вот фрагменты кодов:
var validationParameters = new TokenValidationParameters()
{
RequireExpirationTime = false, // we can check manually
ValidateIssuer = true,
ValidateAudience = true,
.
.
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};
Затем, когда токен проверен, проверьте время истечения срока действия с помощью:
public bool IsExpired(DateTime now)
{
return JwtSecurityToken.ValidTo < Date.UtcNow;
}
Я надеюсь, что этот ответ поможет кому-то.
Для более полного ответа, в вашем Startup.cs:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
// ...
ValidateLifetime = true,
LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken,
TokenValidationParameters validationParameters) =>
{
return notBefore <= DateTime.UtcNow &&
expires >= DateTime.UtcNow;
}
};
});
Почему? Перекос часов будет означать разницу максимум в несколько секунд, что не имеет значения для этого типа приложений ... перекос часов - это проблема, о которой должны беспокоиться цифровые схемы, а не проверка подлинности программного обеспечения.
На серверах действительно случаются дрейфы часов, и это может привести к случайному отклонению / принятию токена в зависимости от сервера, на который вы попали. Причина, по которой это свойство существует, означает, что оно имеет значение.
Кроме того, библиотека ms уже проверяет время в utc, поэтому код, знающий ответ, не дает никакой дополнительной ценности.
Я имею в виду, да, вы правы в том, что ClockSkew это вещь, но по умолчанию ASP.NET установлено на 5 минут... которое будет превышено только в очень редких случаях. ClockSkew обычно всего несколько секунд... так зачем связываться со значением по умолчанию?
Значение по умолчанию 5 мн не будет учитываться в предоставленном вами коде, поскольку оно переопределяет логику проверки срока службы ASP.NET Core.
Нет, это не точно ... если специально не переопределить, по умолчанию установлено значение 5 минут. stackoverflow.com/a/55155711/550975
Взгляните на исходный код или проведите несколько тестов самостоятельно. Когда вы переопределяете проверку времени жизни, это эквивалентно утверждению «Я знаю, что делаю», инфраструктура не выполняет никакой дополнительной проверки времени жизни, так как теперь ответственность за это лежит на разработчике.
Вы ошибаетесь... спасибо, что потратили мое время на поиск исходного кода, но это так, как я сказал... если специально не переопределить, он установлен на 5 минут: github.com/AzureAD/…
Я не понимаю, почему вы отказываетесь понять мою точку зрения. Я никогда не говорил, что по умолчанию не было 5 минут. Я сказал следующее: 1. Ваш ответ не добавляет значение anh, поскольку проверка уже выполнена в utc библиотекой. 2. В вашем ответе не учитывается любое значение, установленное в ClockSkew, а это означает, что пожизненная проверка в вашем коде проверяется только на основе времени истечения срока действия без учета ClockSkew. Я надеюсь, что теперь это ясно для вас. Посмотрите мой ответ, в нем есть ссылка на соответствующий исходный код, который показывает, как ваш код предотвращает учет ClockSkew.
Это уже дело. Пакет System.IdentityModel.Tokens.Jwt действительно проверяет время жизни JWT по времени UTC. Вот соответствующий бит из источника:
public static void ValidateLifetime(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
...
if (notBefore.HasValue && expires.HasValue && (notBefore.Value > expires.Value))
throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidLifetimeException(LogHelper.FormatInvariant(LogMessages.IDX10224, notBefore.Value, expires.Value))
{ NotBefore = notBefore, Expires = expires });
DateTime utcNow = DateTime.UtcNow;
if (notBefore.HasValue && (notBefore.Value > DateTimeUtil.Add(utcNow, validationParameters.ClockSkew)))
throw LogHelper.LogExceptionMessage(new SecurityTokenNotYetValidException(LogHelper.FormatInvariant(LogMessages.IDX10222, notBefore.Value, utcNow))
{ NotBefore = notBefore.Value });
if (expires.HasValue && (expires.Value < DateTimeUtil.Add(utcNow, validationParameters.ClockSkew.Negate())))
throw LogHelper.LogExceptionMessage(new SecurityTokenExpiredException(LogHelper.FormatInvariant(LogMessages.IDX10223, expires.Value, utcNow))
{ Expires = expires.Value });
// if it reaches here, that means lifetime of the token is valid
LogHelper.LogInformation(LogMessages.IDX10239);
}
Это не учитывает настройку ClockSkew.