Como decodificar o token JWT?

101

Não entendo como funciona esta biblioteca. Você poderia me ajudar por favor ?

Aqui está meu código simples:

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

        var jsonToken = handler.ReadToken(stream);
    }

Este é o erro:

A string precisa estar no formato JSON compacto, que tem o formato: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL, Base64UrlEncodedSignature '.

Se você copiar o stream no site jwt.io , funciona bem :)

Cooxkie
fonte
1
o site jwt, io o decodifica, mas como não há assinatura, é inválido.
Crowcoder
1
@MichaelFreidgeim você está certo, é uma pergunta duplicada ... mas as respostas são diferentes por causa da biblioteca de versões que você usa
Cooxkie

Respostas:

175

Eu encontrei a solução, só esqueci de lançar o resultado:

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

Posso obter reivindicações usando:

var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;
Cooxkie
fonte
2
Eu tive que lançar tokenS.Claims como uma lista de reivindicações primeiro. ((List<Claim>)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));
Rinaldi Segecin
12
Você também pode fazer: handler.ReadJwtToken (tokenJwtReponse.access_token);
Thabiso Mofokeng de
13
Desculpe se isso deveria ser óbvio, mas de onde está tokenJwtReponse.access_tokenvindo?
Jeff Stapleton
3
De onde vem o tokenJwtReponse.access_token?
3iL de
4
Como outros já questionaram: de onde vem "tokenJwtReponse.access_token"? Não há definição ou declaração para isso na resposta, tornando a resposta inútil e sem sentido para muitos de nós.
Zeek2
33

new JwtSecurityTokenHandler().ReadToken("") retornará um SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") retornará um JwtSecurityToken

Se você apenas mudar o método que está usando, você pode evitar o elenco na resposta acima

dpix
fonte
16

Você precisa da string secreta que foi usada para gerar o token de criptografia. Este código funciona para mim:

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
fonte
Por que você chama handler.ReadToken(token) as SecurityTokenquando está reatribuindo-o como seu outparâmetro posteriormente? Existe a possibilidade de que ValidateTokenfalhe e o valor original seja mantido?
Krillgar de
Krillgar certo não é necessário o elenco de SecurityToken
Pato Milán
O ValidateToken verifica a validade? Ou eu mesmo preciso validar isso depois de decodificado?
computrius
9

Usando pacotes .net core jwt, as reivindicações estão disponíveis:

[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ão-jenson
fonte
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);

Em seguida, extraia o conteúdo

 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
fonte
3

Estendendo a resposta cooxkie e a resposta dpix , ao ler um token jwt (como um access_token recebido do AD FS), você pode mesclar as declarações no token jwt com as declarações de "context.AuthenticationTicket.Identity" que podem não têm o mesmo conjunto de declarações que o token jwt.

Para ilustrar, em um fluxo de código de autenticação usando OpenID Connect, depois que um usuário é autenticado, você pode manipular o evento SecurityTokenValidated que fornece um contexto de autenticação, então você pode usá-lo para ler o access_token como um token jwt, então você pode " mesclar "tokens que estão no access_token com a lista padrão de declarações recebidas como parte da identidade do usuário:

    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
fonte