Как расшифровать токен JWT?

104

Я не понимаю, как работает эта библиотека. Не могли бы вы мне помочь, пожалуйста ?

Вот мой простой код:

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

        var jsonToken = handler.ReadToken(stream);
    }

Это ошибка:

Строка должна быть в компактном формате JSON, который имеет вид: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL, Base64UrlEncodedSignature '.

Если скопировать поток на сайт jwt.io , все работает нормально :)

Cooxkie
источник
1
сайт jwt, io декодирует его, но подпись отсутствует, поэтому он недействителен.
Crowcoder
1
@MichaelFreidgeim, вы правы, это повторяющийся вопрос ... но ответы разные из-за используемой вами библиотеки версий
Cooxkie

Ответы:

181

Я нашел решение, просто забыл передать результат:

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

Я могу получать претензии, используя:

var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;
Cooxkie
источник
2
Сначала мне пришлось использовать tokenS.Claims как список требований. ((List<Claim>)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));
Ринальди Сегецин
12
Вы также можете: handler.ReadJwtToken (tokenJwtReponse.access_token);
Thabiso Mofokeng,
14
Извините, если это должно быть очевидно, но откуда tokenJwtReponse.access_tokenвзялось?
Джефф Стэплтон
4
Откуда приходит tokenJwtReponse.access_token?
3iL
4
Как уже спрашивали другие: откуда берется «tokenJwtReponse.access_token»? В ответе нет определения или декларации, что делает ответ бесполезным и бессмысленным для многих из нас.
Zeek2 08
35

new JwtSecurityTokenHandler().ReadToken("") вернет SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") вернет JwtSecurityToken

Если вы просто измените метод, который вы используете, вы можете избежать приведенного выше ответа

dpix
источник
16

Вам нужна секретная строка, которая использовалась для генерации токена шифрования. У меня работает этот код:

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;
    }
Пато Милан
источник
Почему вы звоните, handler.ReadToken(token) as SecurityTokenкогда outпозже переназначаете его в качестве параметра? Есть ли вероятность, что ValidateTokenпроизойдет сбой, и исходное значение будет сохранено?
krillgar
Правый крилгар не обязателен в составе SecurityToken
Пато Милан
Проверяет ли ValidateToken истечение срока действия? Или мне нужно подтвердить это самому после того, как он будет декодирован?
computrius
9

При использовании пакетов .net core jwt доступны следующие претензии:

[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;
    }
}
Дженсон-кнопка-событие
источник
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);

Затем извлеките содержимое

 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;
Джинеш
источник
3

Расширение на cooxkie ответ, и DPix ответ, когда вы читаете JWT маркер (например, access_token получил от AD FS), вы можете объединить требования в JWT маркер с претензий от «context.AuthenticationTicket.Identity» , что не может имеют тот же набор требований, что и токен jwt.

Чтобы проиллюстрировать, в потоке кода аутентификации с использованием OpenID Connect после аутентификации пользователя вы можете обработать событие SecurityTokenValidated, которое предоставляет вам контекст аутентификации, затем вы можете использовать его для чтения access_token как токена jwt, тогда вы можете " объединить токены, которые находятся в access_token, со стандартным списком утверждений, полученных как часть удостоверения пользователя:

    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
источник