如何解码JWT令牌?


103

我不了解该库的工作方式。请问你能帮帮我吗 ?

这是我的简单代码:

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

        var jsonToken = handler.ReadToken(stream);
    }

这是错误:

该字符串必须采用紧凑的JSON格式,格式为:Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL,Base64UrlEncodedSignature'。

如果您在jwt.io网站中复制流,则可以正常工作:)


1
jwt,io站点对其进行解码,但是没有签名,因此无效。
Crowcoder '16


1
@MichaelFreidgeim你是对的,这是一个重复的问题...但是由于使用的版本库,答案有所不同
Cooxkie 2017年

Answers:


179

我找到了解决方案,我只是忘了铸造结果:

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;

2
我必须首先将tokenS.Claims转换为“索赔列表”。((List<Claim>)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));
Rinaldi Segecin '17

12
您还可以执行以下操作:handler.ReadJwtToken(tokenJwtReponse.access_token);
Thabiso Mofokeng '18

14
抱歉,这应该很明显,但它tokenJwtReponse.access_token来自哪里?
杰夫·斯塔普尔顿

4
tokenJwtReponse.access_token来自哪里?
3iL

4
正如其他人已经质疑的那样:“ tokenJwtReponse.access_token”来自何处?答案中没有定义或声明,这使得答案对我们许多人来说毫无用处和意义。
Zeek2

35

new JwtSecurityTokenHandler().ReadToken("") 将返回一个 SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") 将返回一个 JwtSecurityToken

如果您只是更改使用的方法,则可以避免在上述答案中进行强制转换


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 '19

右小磷虾不是必要的演员,而是SecurityToken
PatoMilán19年

ValidateToken是否检查到期?还是在解码后我需要验证自己?
computrius

9

使用.net core jwt软件包,可以使用Claims:

[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令牌(例如从AD FS接收的access_token)时,可以将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);
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.