¿Cómo decodificar el Token JWT?

101

No entiendo cómo funciona esta biblioteca. Usted me podría ayudar por favor ?

Aquí está mi código simple:

public void TestJwtSecurityTokenHandler()
    {
        var stream =
            "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJJU1MiLCJzY29wZSI6Imh0dHBzOi8vbGFyaW0uZG5zY2UuZG91YW5lL2NpZWxzZXJ2aWNlL3dzIiwiYXVkIjoiaHR0cHM6Ly9kb3VhbmUuZmluYW5jZXMuZ291di5mci9vYXV0aDIvdjEiLCJpYXQiOiJcL0RhdGUoMTQ2ODM2MjU5Mzc4NClcLyJ9";
        var handler = new JwtSecurityTokenHandler();

        var jsonToken = handler.ReadToken(stream);
    }

Este es el error:

La cadena debe estar en formato JSON compacto, que tiene el formato: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL, Base64UrlEncodedSignature '.

Si copia la secuencia en el sitio web jwt.io , funciona bien :)

Cooxkie
fuente
1
el sitio jwt, io lo decodifica, pero no hay firma, por lo que no es válido.
Crowcoder
1
@MichaelFreidgeim tienes razón, es una pregunta duplicada ... pero las respuestas son diferentes debido a la biblioteca de versiones que usas
Cooxkie

Respuestas:

175

Encontré la solución, solo olvidé enviar el resultado:

var stream ="[encoded jwt]";  
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
var tokenS = handler.ReadToken(stream) as JwtSecurityToken;

Puedo obtener reclamos usando:

var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;
Cooxkie
fuente
2
Primero tuve que lanzar tokenS.Claims como una lista de reclamos. ((List<Claim>)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));
Rinaldi Segecin
12
También puede hacer: handler.ReadJwtToken (tokenJwtReponse.access_token);
Thabiso Mofokeng
13
Lo siento si esto debería ser obvio, pero ¿de dónde tokenJwtReponse.access_tokenviene?
Jeff Stapleton
3
¿De dónde viene tokenJwtReponse.access_token?
3iL
4
Como otros ya han cuestionado: ¿de dónde viene "tokenJwtReponse.access_token"? No hay una definición o declaración para ello en la respuesta, lo que hace que la respuesta sea inútil y sin sentido para muchos de nosotros.
Zeek2
33

new JwtSecurityTokenHandler().ReadToken("") devolverá un SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") devolverá un JwtSecurityToken

Si solo cambia el método que está utilizando, puede evitar el yeso en la respuesta anterior

dpix
fuente
16

Necesita la cadena secreta que se utilizó para generar el token de cifrado. Este código funciona para mí:

protected string GetName(string token)
    {
        string secret = "this is a string used for encrypt and decrypt token"; 
        var key = Encoding.ASCII.GetBytes(secret);
        var handler = new JwtSecurityTokenHandler();
        var validations = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false
        };
        var claims = handler.ValidateToken(token, validations, out var tokenSecure);
        return claims.Identity.Name;
    }
Pato Milán
fuente
¿Por qué llama handler.ReadToken(token) as SecurityTokencuando lo reasigna como outparámetro más tarde? ¿Existe la posibilidad de que ValidateTokenfalle y se mantenga el valor original?
krillgar
Derecho krillgar no es necesario el elenco de SecurityToken
Pato Milán
¿ValidateToken verifica el vencimiento? ¿O necesito validarlo yo mismo después de decodificarlo?
Computrius
9

Con los paquetes .net core jwt, las reclamaciones están disponibles:

[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "Bearer")]
public class AbstractController: ControllerBase
{
    protected string UserId()
    {
        var principal = HttpContext.User;
        if (principal?.Claims != null)
        {
            foreach (var claim in principal.Claims)
            {
               log.Debug($"CLAIM TYPE: {claim.Type}; CLAIM VALUE: {claim.Value}");
            }

        }
        return principal?.Claims?.SingleOrDefault(p => p.Type == "username")?.Value;
    }
}
evento-botón-jenson
fuente
6
  var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var claims = new[]
                {
                    new Claim(JwtRegisteredClaimNames.Email, model.UserName),
                    new Claim(JwtRegisteredClaimNames.NameId, model.Id.ToString()),
                };
        var token = new JwtSecurityToken(_config["Jwt:Issuer"],
          _config["Jwt:Issuer"],
          claims,
          expires: DateTime.Now.AddMinutes(30),
          signingCredentials: creds);

Luego extrae el contenido

 var handler = new JwtSecurityTokenHandler();
        string authHeader = Request.Headers["Authorization"];
        authHeader = authHeader.Replace("Bearer ", "");
        var jsonToken = handler.ReadToken(authHeader);
        var tokenS = handler.ReadToken(authHeader) as JwtSecurityToken;

        var id = tokenS.Claims.First(claim => claim.Type == "nameid").Value;
Jinesh
fuente
3

Ampliando la respuesta de cooxkie y la respuesta de dpix , cuando está leyendo un token de jwt (como un access_token recibido de AD FS), puede combinar las notificaciones en el token de jwt con las notificaciones de "context.AuthenticationTicket.Identity" que podrían no tienen el mismo conjunto de notificaciones que el token jwt.

Para ilustrar, en un flujo de código de autenticación usando OpenID Connect, después de que un usuario está autenticado, puede manejar el evento SecurityTokenValidated que le proporciona un contexto de autenticación, luego puede usarlo para leer el access_token como un token jwt, luego puede " fusionar "tokens que están en access_token con la lista estándar de reclamos recibidos como parte de la identidad del usuario:

    private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage,OpenIdConnectAuthenticationOptions> context)
    {
        //get the current user identity
        ClaimsIdentity claimsIdentity = (ClaimsIdentity)context.AuthenticationTicket.Identity;

        /*read access token from the current context*/
        string access_token = context.ProtocolMessage.AccessToken;

        JwtSecurityTokenHandler hand = new JwtSecurityTokenHandler();
        //read the token as recommended by Coxkie and dpix
        var tokenS = hand.ReadJwtToken(access_token);
        //here, you read the claims from the access token which might have 
        //additional claims needed by your application
        foreach (var claim in tokenS.Claims)
        {
            if (!claimsIdentity.HasClaim(claim.Type, claim.Value))
                claimsIdentity.AddClaim(claim);
        }

        return Task.FromResult(0);
    }
TamerDev
fuente