Jak zdekodować token JWT?

103

Nie rozumiem, jak działa ta biblioteka. Proszę, mógłbyś mi pomóc ?

Oto mój prosty kod:

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

        var jsonToken = handler.ReadToken(stream);
    }

To jest błąd:

Ciąg musi być w kompaktowym formacie JSON, który ma postać: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL, Base64UrlEncodedSignature '.

Jeśli skopiujesz strumień na stronie jwt.io , działa dobrze :)

Cooxkie
źródło
1
strona jwt, io dekoduje go, ale nie ma podpisu, więc jest nieprawidłowy.
Crowcoder
1
@MichaelFreidgeim masz rację, to zduplikowane pytanie ... ale odpowiedzi są różne z powodu biblioteki wersji, której używasz
Cooxkie

Odpowiedzi:

179

Znalazłem rozwiązanie, po prostu zapomniałem przesłać wynik:

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

Mogę otrzymać roszczenia za pomocą:

var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;
Cooxkie
źródło
2
Najpierw musiałem rzucić tokenS.Claims jako listę roszczeń. ((List<Claim>)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));
Rinaldi Segecin
12
Możesz też: handler.ReadJwtToken (tokenJwtReponse.access_token);
Thabiso Mofokeng,
14
Przepraszam, jeśli to powinno być oczywiste, ale skąd tokenJwtReponse.access_tokenpochodzi?
Jeff Stapleton
4
Skąd pochodzi tokenJwtReponse.access_token?
3iL
4
Jak już inni zadawali pytania: skąd pochodzi „tokenJwtReponse.access_token”? W odpowiedzi nie ma na to definicji ani deklaracji, przez co dla wielu z nas jest ona bezużyteczna i bez znaczenia.
Zeek2
35

new JwtSecurityTokenHandler().ReadToken("") zwróci plik SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") zwróci plik JwtSecurityToken

Jeśli zmienisz tylko metodę, której używasz, możesz uniknąć obsady w powyższej odpowiedzi

dpix
źródło
16

Potrzebujesz tajnego ciągu, który został użyty do wygenerowania tokena szyfrowania. Ten kod działa dla mnie:

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
źródło
Dlaczego dzwonisz, handler.ReadToken(token) as SecurityTokengdy outpóźniej ponownie przypisujesz go jako parametr? Czy istnieje możliwość, że ValidateTokenzawiedzie i zachowana zostanie pierwotna wartość?
krillgar
Właściwy krillgar nie jest konieczny w obsadzie SecurityToken
Pato Milán
Czy ValidateToken sprawdza datę ważności? Czy też muszę potwierdzić to samodzielnie po zdekodowaniu?
computrius
9

Korzystając z pakietów .net core jwt, dostępne są oświadczenia:

[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;
    }
}
jenson-button-event
źródło
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);

Następnie wyodrębnij zawartość

 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
źródło
3

Rozszerzając odpowiedź cooxkie i odpowiedź dpix , kiedy czytasz token jwt (taki jak access_token otrzymany z AD FS), możesz scalić oświadczenia w tokenie jwt z oświadczeniami z „context.AuthenticationTicket.Identity”, które może nie mają ten sam zestaw oświadczeń co token jwt.

Aby zilustrować, w przepływie kodu uwierzytelniającego przy użyciu OpenID Connect, po uwierzytelnieniu użytkownika, możesz obsłużyć zdarzenie SecurityTokenValidated, które zapewnia kontekst uwierzytelniania, a następnie możesz go użyć do odczytania access_token jako tokena jwt, a następnie możesz " merge ”tokeny znajdujące się w access_token ze standardową listą oświadczeń otrzymanych w ramach tożsamości użytkownika:

    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
źródło