Comment décoder le jeton JWT?

102

Je ne comprends pas comment cette bibliothèque fonctionne. Pourrais-tu m'aider s'il te plait ?

Voici mon code simple:

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

        var jsonToken = handler.ReadToken(stream);
    }

Voici l'erreur:

La chaîne doit être au format JSON compact, qui est de la forme: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL, Base64UrlEncodedSignature '.

Si vous copiez le flux sur le site Web jwt.io , cela fonctionne très bien :)

Cooxkie
la source
1
le site jwt, io le décode, mais il n'y a pas de signature donc il n'est pas valide.
Crowcoder
Double
1
@MichaelFreidgeim vous avez raison, c'est une question en double ... mais les réponses sont différentes en raison de la bibliothèque de versions que vous utilisez
Cooxkie

Réponses:

176

J'ai trouvé la solution, j'ai juste oublié de diffuser le résultat:

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

Je peux obtenir des réclamations en utilisant:

var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;
Cooxkie
la source
2
J'ai d'abord dû lancer tokenS.Claims en tant que liste de revendications. ((List<Claim>)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));
Rinaldi Segecin
12
Vous pouvez également faire: handler.ReadJwtToken (tokenJwtReponse.access_token);
Thabiso Mofokeng
13
Désolé si cela devrait être évident, mais d'où tokenJwtReponse.access_tokenvient-il?
Jeff Stapleton
3
D'où vient tokenJwtReponse.access_token?
3iL
4
Comme d'autres l'ont déjà posé la question: d'où vient "tokenJwtReponse.access_token"? Il n'y a pas de définition ou de déclaration pour cela dans la réponse, ce qui rend la réponse inutile et dénuée de sens pour beaucoup d'entre nous.
Zeek2
33

new JwtSecurityTokenHandler().ReadToken("") retournera un SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") retournera un JwtSecurityToken

Si vous changez simplement la méthode que vous utilisez, vous pouvez éviter le casting dans la réponse ci-dessus

dpix
la source
16

Vous avez besoin de la chaîne secrète qui a été utilisée pour générer le jeton de chiffrement. Ce code fonctionne pour moi:

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
la source
Pourquoi appelez handler.ReadToken(token) as SecurityToken-vous lorsque vous le réaffectez en tant que outparamètre plus tard? Y a-t-il une possibilité d' ValidateTokenéchec et la valeur d'origine est conservée?
krillgar
Right krillgar n'est pas nécessaire pour le casting de SecurityToken
Pato Milán
ValidateToken vérifie-t-il l'expiration? Ou dois-je le valider moi-même après le décodage?
computrius le
9

En utilisant les packages .net core jwt, les revendications sont 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;
    }
}
événement jenson-button
la source
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);

Puis extraire le contenu

 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
la source
3

En étendant la réponse cooxkie et la réponse dpix , lorsque vous lisez un jeton jwt (tel qu'un access_token reçu d'AD FS), vous pouvez fusionner les revendications du jeton jwt avec les revendications de "context.AuthenticationTicket.Identity" qui pourraient ne pas ont le même ensemble de revendications que le jeton jwt.

Pour illustrer, dans un flux de code d'authentification utilisant OpenID Connect, une fois qu'un utilisateur est authentifié, vous pouvez gérer l'événement SecurityTokenValidated qui vous fournit un contexte d'authentification, puis vous pouvez l'utiliser pour lire le access_token en tant que jeton jwt, puis vous pouvez " fusionner "les jetons qui se trouvent dans le jeton d'accès avec la liste standard des revendications reçues dans le cadre de l'identité de l'utilisateur:

    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
la source