Jwt - data z validTo - godzina różnicy

0

Cześć,

próbuję zrobić autoryzację za pomocą JWT w .net core 3.1.

Mam problemy z datą. Dostaję informację, że token wygasł nawet jak jeszcze nie powinien.

Poniżej kod, którym generuję token.

var claims = new[]
            {
                new Claim("Id", user.tt_id.ToString()),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            };

            var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration.SecretKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var expiredOn = DateTime.UtcNow.AddMinutes(configuration.TokenExpirationTime);
            var token = new JwtSecurityToken(configuration.ValidIssuer,
                  configuration.ValidAudience,
                  claims,
                  expires: expiredOn,
                  signingCredentials: creds);

Wrzucam też przykładowy token JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJZCI6IjEiLCJqdGkiOiI0Mzk5ZDdmYS1mNzVmLTQ2NWYtYjFiMS1kMjgwOWE0N2IxZWIiLCJleHAiOjE2MTE5MzYyNjgsImlzcyI6IkM1RDNBNDYwLUFGNUYtMzNGRi05NjAwLTMwMDQ2MDc3NEZGOSIsImF1ZCI6IjYyMUI2MkIwLTgzQzItS0s1Ny1CRUFGLTkzNjJEM0QzMUVDNSJ9.ryaxAF7RvFodgLL-jFFvDAETTxG50GK_3gYwNNAajgQ

Powinien być on ważny 3 minuty, jednak tak nie jest. Mam wrażenie, że problem jest z różnicą czasową między UTC.

Wrzucam też moją konfigurację z Starrtup:

var serviceProvider = services.BuildServiceProvider();

            var config = services.BuildServiceProvider().GetService<JWTConfiguration>();
            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.SecretKey));

            var tokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKey = signingKey,
                ValidIssuer = config.ValidIssuer,
                ValidAudience = config.ValidAudience,
                ClockSkew = TimeSpan.Zero
            };

            services.AddAuthentication(o =>
            {
                o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(c =>
            {
                c.RequireHttpsMetadata = false;
                c.SaveToken = true;
                c.TokenValidationParameters = tokenValidationParameters;
                c.Events = new JwtBearerEvents
                {
                    OnTokenValidated = context =>
                    {
                        var userService = serviceProvider.GetService<IUserService>();

                        if (!userService.CheckJwtToken(context.Request.Headers[HeaderNames.Authorization]).Result)
                            context.Fail("Błędny token.");

                        return Task.CompletedTask;
                    }
                };
            });

W postmanie dostaję:
screenshot-20210129170834.png

Jeżeli zrobię ważność tokenu an ponad godzinę to wtedy jest ok (jakbym miał tą godzinę ważności cofniętą).

Nie bardzo wiem, jak to poprawić. Proszę o pomoc

1

W podanym przez ciebie tokenie expires jest = 1611936268 = 29/01/2021 1728 (GMT +1), a o której go wystawiłeś?

Tu masz debugger https://jwt.io/ sprawdź sobię

RFC JWT mówi że:

4.1.4. "exp" (Expiration Time) Claim
Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL.

A Stackoverflow mówi że

NumericDate is the last definition in Section 2. Terminology, and is defined as the number of seconds (not milliseconds) since Epoch:

A JSON numeric value representing the number of seconds from 1970-01-01T0000Z UTC until the specified UTC date/time, ignoring leap seconds. This is equivalent to the IEEE Std 1003.1, 2013 Edition [POSIX.1] definition "Seconds Since the Epoch", in which each day is accounted for by exactly 86400 seconds, other than that non-integer values can be represented. See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular.

A dokumentacja MS mówi że:

DateTime.UtcNow
Gets a DateTime object that is set to the current date and time on this computer, expressed as the Coordinated Universal Time (UTC).

A Wiki mówi że:

The coordination of time and frequency transmissions around the world began on 1 January 1960.

Czy stąd nie wynika rozjazd?

Czy przypadkiem nie trzeba użyć czegoś z ToUnixTimeSeconds()? Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z.

DateTime foo = DateTime.Now;
long unixTime = ((DateTimeOffset)foo).ToUnixTimeSeconds();

wydaje się działać, ale ręki nie dam

public static class Ext
{
	public static long ToUnixTimestamp(this DateTime date)
	{
		var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
		var time = date.ToUniversalTime().Subtract(epoch);
		return time.Ticks / TimeSpan.TicksPerSecond;
	}
}

var dt = DateTime.Now.AddMinutes(15);
var exp = dt.ToUnixTimestamp();

Stronka do testu https://www.unixtimestamp.com/

0
WeiXiao napisał(a):

W podanym przez ciebie tokenie expires jest = 1611936268 = 29/01/2021 1728 (GMT +1), a o której go wystawiłeś?

3 minuty wcześniej.

Tu masz debugger https://jwt.io/ sprawdź sobię
Sprawdzałem właśnie.

RFC JWT mówi że:

4.1.4. "exp" (Expiration Time) Claim
Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL.

A Stackoverflow mówi że

NumericDate is the last definition in Section 2. Terminology, and is defined as the number of seconds (not milliseconds) since Epoch:

A JSON numeric value representing the number of seconds from 1970-01-01T0000Z UTC until the specified UTC date/time, ignoring leap seconds. This is equivalent to the IEEE Std 1003.1, 2013 Edition [POSIX.1] definition "Seconds Since the Epoch", in which each day is accounted for by exactly 86400 seconds, other than that non-integer values can be represented. See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular.

A dokumentacja MS mówi że:

DateTime.UtcNow
Gets a DateTime object that is set to the current date and time on this computer, expressed as the Coordinated Universal Time (UTC).

A Wiki mówi że:

The coordination of time and frequency transmissions around the world began on 1 January 1960.

Czy stąd nie wynika rozjazd?

Czy przypadkiem nie trzeba użyć czegoś z ToUnixTimeSeconds()? Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z.

Konstruktor przyjmuje również DateTime.

DateTime foo = DateTime.Now;
long unixTime = ((DateTimeOffset)foo).ToUnixTimeSeconds();

wydaje się działać, ale ręki nie dam

public static class Ext
{
	public static long ToUnixTimestamp(this DateTime date)
	{
		var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
		var time = date.ToUniversalTime().Subtract(epoch);
		return time.Ticks / TimeSpan.TicksPerSecond;
	}
}

var dt = DateTime.Now.AddMinutes(15);
var exp = dt.ToUnixTimestamp();

Właśnie dziwi mnie jeszcze, że DateTime.Now zwraca mi np. godzinę 17:03, a api (na razie localhost) jak odpowiada na requesty to w headerze jest godzina mniej. Może coś tutaj jest nie tak?

        //
        // Summary:
        //     Initializes a new instance of the System.IdentityModel.Tokens.Jwt.JwtSecurityToken
        //     class specifying optional parameters.
        //
        // Parameters:
        //   issuer:
        //     If this value is not null, a { iss, 'issuer' } claim will be added.
        //
        //   audience:
        //     If this value is not null, a { aud, 'audience' } claim will be added
        //
        //   claims:
        //     If this value is not null then for each System.Security.Claims.Claim a { 'Claim.Type',
        //     'Claim.Value' } is added. If duplicate claims are found then a { 'Claim.Type',
        //     List<object> } will be created to contain the duplicate values.
        //
        //   expires:
        //     If expires.HasValue a { exp, 'value' } claim is added.
        //
        //   notBefore:
        //     If notbefore.HasValue a { nbf, 'value' } claim is added.
        //
        //   signingCredentials:
        //     The System.IdentityModel.Tokens.Jwt.JwtSecurityToken.SigningCredentials that
        //     will be used to sign the System.IdentityModel.Tokens.Jwt.JwtSecurityToken. See
        //     System.IdentityModel.Tokens.Jwt.JwtHeader.#ctor(Microsoft.IdentityModel.Tokens.SigningCredentials)
        //     for details pertaining to the Header Parameter(s).
        //
        // Exceptions:
        //   T:System.ArgumentException:
        //     If 'expires' <= 'notbefore'.
        public JwtSecurityToken(string issuer = null, string audience = null, IEnumerable<Claim> claims = null, DateTime? notBefore = null, DateTime? expires = null, SigningCredentials signingCredentials = null);
2

Tutaj problemem chyba jest to że data wygaśnięcia jest w UTC+1. Nie jest czasem tak że walidacja po stronie serwera porównuje to z UTC+0 (Zulu)? Obliczając wygaśnięcie spróbuj ustawić datę bazując na UtcNow.

W przypadku tokenów nie ma sensu bawić się w strefy czasowe tylko bazować właśnie na UTC+0. Koniec końców celem jest wygaśnięcie tokena po X minutach/godzinach/dniach, a nie wartość relatywna tej daty.

0

Ustawienie wszędzie UTCNow zamiast zwykłego Now rozwiązało problem ;)

Dzięki

1 użytkowników online, w tym zalogowanych: 0, gości: 1