Actualmente estoy usando la clase JwtSecurityToken en el espacio de nombres System.IdentityModels.Tokens. Creo un token usando lo siguiente:
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);
Por alguna razón, aunque la caducidad está configurada en 10 segundos después de la hora actual, en realidad no genera una excepción cuando el token se valida hasta aproximadamente 5 minutos. Después de ver esto, pensé que tal vez había un tiempo mínimo de caducidad de 5 minutos, así que configuré el tiempo de caducidad en:
DateTime.UtcNow.AddMinutes(5);
Luego caduca a los 10 minutos, pero el mensaje de excepción dice que el tiempo de caducidad está establecido en lo que se supone que es (5 minutos después de que el usuario inicia sesión), y cuando muestra la hora actual en la excepción es 5 minutos después del tiempo de caducidad. Entonces, parece saber cuándo DEBE caducar, pero en realidad no arroja elexcepción hasta 5 minutos después del tiempo de caducidad. Luego, dado que el token parece estar agregando 5 minutos al tiempo que configuré para que caduque, configuré el tiempo de caducidad en:
DateTime.UtcNow.AddMinutes(-5).AddSecond(10);
Probé esto y hasta ahora todavía no ha caducado (después de más de diez minutos). ¿Alguien puede explicar por qué sucede esto y qué estoy haciendo mal? Además, si ve algo más con el código que proporcioné, agradecería cualquier orientación ya que soy nuevo en el uso de JWT y esta biblioteca.
El problema está relacionado con ClockSkew. Normalmente, las bibliotecas de validación (al menos la de MS) compensan la desviación del reloj. Valor predeterminado de ClockSkewEl valor es de 5 minutos. Vea alguna respuesta aquí
Puedes cambiar ClockSkew en TokenValidationParameters:
var tokenValidationParameters = new TokenValidationParameters
{
//...your setting
// set ClockSkew is zero
ClockSkew = TimeSpan.Zero
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters
});
Respondido al 15 de septiembre de 2017 a las 3:11
HienHien
2.060
2
2 insignias de oro
18
18 insignias de plata
14
14 insignias de bronce
0
Después de leer la respuesta de @Denis Kucherov, descubrí que podía usar el mismo validador personalizado que élpublicado sin usar la clase JwtBearerOptions, lo que me habría requerido agregar una nueva biblioteca.
Además, dado que hay dos espacios de nombres que contienen muchas de estas mismas clases, me aseguraré de mencionar que todos ellos utilizan los espacios de nombres System.IdentityModels.... (NO Microsoft.IdentityModels...)
A continuación se muestra el código que terminé usando:
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;
}
Parece haber algún problema con LifeTimeValidator. Puedes simplemente anular su lógica con un delegado personalizado. Además, utilice la clase JwtBearerOptions para controlar el comportamiento del middleware de autenticación. Por ejemplo:
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"]))
}
}
Y asigne un delegado LifetimeValidotor para proporcionar su propia lógica de validación de tiempo de espera:
private bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken token, TokenValidationParameters @params)
{
if (expires != null)
{
return expires > DateTime.UtcNow;
}
return false;
}
Respondido 14/08/2017 a las 14:00
Denis KucherovDenis Kucherov
379
3
3 insignias de plata
15
15 insignias de bronce
5
JwtBearerOptions parece requerir otra biblioteca. Lo comprobé aquí:nuget.org/packages/Microsoft.AspNet.Authentication.JwtBearer e intenté instalar nuget. Falla cada vez, a pesar de que mi proyecto está en .net 4.5.1. "No se pudo instalar el paquete 'Microsoft.AspNet.Authentication.JwtBearer 1.0.0-beta8'. Está intentando instalar este paquete en un proyecto destinado a '.NETFramework,Version=v4.5.1', pero el paquete no contiene ninguna referencia de ensamblado ni archivos de contenido que sean compatibles con ese marco". ¿Alguna idea de por qué no me deja instalar?
-tkd_aj18/08/2017 a las 20:40
@tkd_aj- Pruebe este: nuget.org/packages/…
- Denis Kucherov19/08/2017 a las 6:28
Ese es para ASP.NET Core. Nuestro proyecto utiliza ASP.NET 4.5.1. Supongo que eso no va a funcionar.
-tkd_aj21/08/2017 a las 20:04
@tkd_aj Pruebe la versión 1.1.2, debería funcionar en 4.5.1 y .NET Standart 1.4
- Denis Kucherov22/08/2017 a las 8:46
Esa versión de la biblioteca se instaló correctamente. Sin embargo, después de instalarlo, no pude encontrar una manera de USAR realmente el objeto JwtBearerOptions que había creado. Miré por todas partes y solo encontré que se usaba en ASP.NET core como middleware usando el método app.use(). PERO, mientras exploraba, descubrí que podía asignar el mismo validador personalizado que publicaste anteriormente en mi código existente donde estaba validando elsimbólico. Votaré tu respuesta y publicaré el código que terminé usando al final. ¡Gracias por ayudarme a resolver este problema!
-tkd_aj25/08/2017 a las 17:22
Esto se maneja de manera ligeramente diferente en .NET Core, ya que los TokenValidationParameters se configuran en Startup.cs usando el método ConfigureServices() y luego el middleware los maneja automáticamente.
Tenga en cuenta también que la antigua InMemorySymmetricSecurityKey para firmar el secreto ahora está obsoleta en favor de SymmetricSecurityKey, que se muestra a continuación.
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = _config.AuthenticationSettings.TokenAuthority,
ValidAudience = _config.AuthenticationSettings.TokenAuthority,
LifetimeValidator = TokenLifetimeValidator.Validate,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_config.AuthenticationSettings.SecurityKey))
};
});
// ...
}
Y entonces también hice mi propia versión del validador de tokens en @tla respuesta de kd_aj anterior y la arrojó en una clase estática:
public static class TokenLifetimeValidator
{
public static bool Validate(
DateTime? notBefore,
DateTime? expires,
SecurityToken tokenToValidate,
TokenValidationParameters @param
) {
return (expires != null && expires > DateTime.UtcNow);
}
}
1
Esto casi funciona. Sin embargo, llamar a tokenHandler.ValidateToken(...) ahora generará una SecurityTokenInvalidLifetimeException cuando el método Validate devuelva false.
- Jens18/03/2021 a las 22:16
Acabo de implementar también un middleware de token JWT y, aunque los ejemplos en Internet usan UtcNow, tuve que usar Now o el tiempo de caducidad se acabó. Cuando uso Now, la caducidad es perfecta.
3
¿Estás utilizando la versión 5.0 de la biblioteca Jwt? ¿O estás usando el núcleo Asp.Net? Comencé a usar DateTime. Ahora tuve el mismo problema. Desafortunadamente, estoy usando la biblioteca 4.0 porque no podemos usar .NET 4.5. La versión 5.0 de la biblioteca Jwt requiere .NET 4.6, por lo que no podemos usarla.
-tkd_aj27/09/2016 a las 23:27
@tkd_aj - ah... estoy usando Core. Tuve el problema del tiempo libre al usar UtcNow, YMMV :).
- Mazo27/09/2016 a las 23:38
Ah, sí. Vi que AspNet core en realidad tenía un paquete nuget que podías descargar y haría el middleware por ti... Desafortunadamente, eso no está disponible para .NET 4.5. Gracias¡Pero por tu comentario!
-tkd_aj28/09/2016 a las 1:50
El siguiente enlace le brinda la respuesta exacta, ya que de forma predeterminada, MS tiene un tiempo de caducidad de 5 minutos. Entonces, o tienes que hacerlo a medida o con tiempo que cederás. caduca: DateTime.Now.AddSeconds(30) Se agregarán 30 segundos en la línea anterior al tiempo de vencimiento. Por lo tanto, el tiempo total de caducidad será de 5 minutos y 30 segundos
https://github.com/IdentityServer/IdentityServer3/issues/1251
Espero que esto ayude.