จะถอดรหัส JWT Token ได้อย่างไร?


113

ฉันไม่เข้าใจว่าห้องสมุดนี้ทำงานอย่างไร คุณช่วยฉันได้ไหม

นี่คือรหัสง่ายๆของฉัน:

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


1
@MichaelFreidgeim คุณพูดถูกมันเป็นคำถามที่ซ้ำกัน ... แต่คำตอบแตกต่างกันเนื่องจากไลบรารีเวอร์ชันที่คุณใช้
Cooxkie

คำตอบ:


191

ฉันพบวิธีแก้ปัญหาฉันลืมที่จะแคสต์ผลลัพธ์:

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 เรียกร้องเป็น List of Claims ก่อน ((List<Claim>)tokenS.Claims).ForEach(a => Console.WriteLine(a.Type.ToString() + " " + a.Value));
Rinaldi Segecin

13
คุณยังสามารถทำได้: handler.ReadJwtToken (tokenJwtReponse.access_token);
Thabiso Mofokeng

15
ขออภัยหากสิ่งนี้ควรชัดเจน แต่tokenJwtReponse.access_tokenมาจากไหน
Jeff Stapleton

4
tokenJwtReponse.access_token มาจากไหน?
3iL

5
อย่างที่คนอื่นตั้งคำถามไว้แล้วว่า "tokenJwtReponse.access_token" มาจากไหน? ไม่มีคำจำกัดความหรือคำประกาศสำหรับคำตอบนี้ทำให้คำตอบนั้นไร้ประโยชน์และไม่มีความหมายสำหรับพวกเราหลายคน
Zeek2

39

new JwtSecurityTokenHandler().ReadToken("") จะส่งคืนไฟล์ SecurityToken

new JwtSecurityTokenHandler().ReadJwtToken("") จะส่งคืนไฟล์ JwtSecurityToken

หากคุณเพียงแค่เปลี่ยนวิธีการที่คุณใช้คุณสามารถหลีกเลี่ยงนักแสดงในคำตอบข้างต้นได้


18

คุณต้องมีสตริงลับที่ใช้ในการสร้างโทเค็นเข้ารหัส รหัสนี้ใช้ได้กับฉัน:

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
Pato Milán

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;
    }
}

9
  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);
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.