Giải mã và xác minh mã thông báo JWT bằng System.IdentityModel.Tokens.Jwt


101

Tôi đang sử dụng thư viện JWT để giải mã Mã thông báo web Json và muốn chuyển sang triển khai JWT chính thức của Microsoft, System.IdentityModel.Tokens.Jwt .

Tài liệu rất thưa thớt, vì vậy tôi đang gặp khó khăn trong việc tìm cách thực hiện những gì tôi đang làm với thư viện JWT. Với thư viện JWT, có một phương thức Giải mã lấy JWT được mã hóa base64 và biến nó thành JSON mà sau đó có thể được giải mã. Tôi muốn làm điều gì đó tương tự bằng cách sử dụng System.IdentityModel.Tokens.Jwt, nhưng sau một thời gian đào bới, không thể tìm ra cách.

Đối với những gì nó đáng giá, tôi đang đọc mã thông báo JWT từ một cookie, để sử dụng với khung nhận dạng của Google.

Bất kỳ trợ giúp sẽ được đánh giá cao.



Đây là câu trả lời thực tế về cách tìm nạp chứng chỉ Google và xác minh mã thông báo - stackoverflow.com/questions/29757140/…
rothschild86

Câu trả lời:


147

Trong gói có một lớp được gọi là JwtSecurityTokenHandlerdẫn xuất từ System.IdentityModel.Tokens.SecurityTokenHandler. Trong WIF, đây là lớp cốt lõi để giải mã và tuần tự hóa mã thông báo bảo mật.

Lớp có một ReadToken(String)phương thức sẽ lấy chuỗi JWT được mã hóa base64 của bạn và trả về một chuỗi SecurityTokenđại diện cho JWT.

SecurityTokenHandlercũng có một ValidateToken(SecurityToken)phương thức lấy của bạn SecurityTokenvà tạo ra một ReadOnlyCollection<ClaimsIdentity>. Thông thường đối với JWT, điều này sẽ chứa một ClaimsIdentityđối tượng có một tập hợp các yêu cầu đại diện cho các thuộc tính của JWT ban đầu.

JwtSecurityTokenHandlerxác định một số quá tải bổ sung ValidateToken, cụ thể là nó có ClaimsPrincipal ValidateToken(JwtSecurityToken, TokenValidationParameters)quá tải. Đối TokenValidationParameterssố cho phép bạn chỉ định chứng chỉ ký mã thông báo (dưới dạng danh sách X509SecurityTokens). Nó cũng có một quá tải lấy JWT như một stringthay vì a SecurityToken.

Mã để thực hiện việc này khá phức tạp, nhưng bạn có thể tìm thấy mã Global.asax.cx ( TokenValidationHandlerlớp) trong mẫu nhà phát triển có tên "ADAL - Dịch vụ Native App to REST - Authentication with ACS via Browser Dialog", có tại

http://code.msdn.microsoft.com/AAL-Native-App-to-REST-de57f2cc

Ngoài ra, JwtSecurityTokenlớp có các phương thức bổ sung không có trên SecurityTokenlớp cơ sở , chẳng hạn như một thuộc Claimstính nhận các yêu cầu được chứa mà không cần thông qua ClaimsIdentitybộ sưu tập. Nó cũng có một thuộc Payloadtính trả về một JwtPayloadđối tượng cho phép bạn lấy JSON thô của mã thông báo. Nó phụ thuộc vào kịch bản của bạn mà cách tiếp cận nó phù hợp nhất.

Tài liệu chung (tức là không phải JWT cụ thể) cho SecurityTokenHandlerlớp có tại

http://msdn.microsoft.com/en-us/library/system.identitymodel.tokens.securitytokenhandler.aspx

Tùy thuộc vào ứng dụng của bạn, bạn có thể định cấu hình trình xử lý JWT vào đường ống WIF chính xác như bất kỳ trình xử lý nào khác.

Có 3 mẫu của nó được sử dụng trong các loại ứng dụng khác nhau tại

http://code.msdn.microsoft.com/site/search?f%5B0%5D.Type=SearchText&f%5B0%5D.Value=aal&f%5B1%5D.Type=User&f%5B1%5D.Value=Azure% 20AD% 20Developer% 20Experience% 20Team & f% 5B1% 5D.Text = Azure% 20AD% 20Developer% 20Experience% 20Team

Có thể, một cái sẽ phù hợp với nhu cầu của bạn hoặc ít nhất là có thể thích ứng với chúng.


3
Tôi thực sự đánh giá cao câu trả lời của bạn. Vì vậy, khi tôi có ClaimsIdentity, làm cách nào để xác minh nó dựa trên khóa công khai? Cụ thể, tôi đang cố gắng xác minh bộ công cụ nhận dạng của google JWT dựa trên khóa công khai của họ ( gstatic.com/authtoolkit/cert/gitkit_cert.pem )
w.brian

4
Đã cập nhật câu trả lời của tôi - Tôi không thể tìm nguồn đầy đủ cho điều này, nhưng tôi đã chỉ cho bạn hướng của mẫu nhà phát triển thích hợp. Hy vọng nó giúp.
Mike Goodwin

4
@ w.brian - Tôi cũng đang cố gắng làm như vậy. Tôi có một mã thông báo mà tôi có thể giải mã và một khóa công khai mà tôi muốn xác minh, nhưng ngay cả khi nhìn vào những mẫu này, tôi vẫn đang vật lộn để xem cách tôi thực hiện việc này. Bạn có bất kỳ gợi ý nào về mã nào thực sự đã giúp bạn không? Cảm ơn.
Barguast

25

Tôi chỉ tự hỏi tại sao phải sử dụng một số thư viện để giải mã và xác minh mã thông báo JWT.

Mã thông báo JWT được mã hóa có thể được tạo bằng mã giả sau

var headers = base64URLencode(myHeaders);
var claims = base64URLencode(myClaims);
var payload = header + "." + claims;

var signature = base64URLencode(HMACSHA256(payload, secret));

var encodedJWT = payload + "." + signature;

Nó rất dễ thực hiện mà không cần bất kỳ thư viện cụ thể nào. Sử dụng mã sau:

using System;
using System.Text;
using System.Security.Cryptography;

public class Program
{   
    // More info: https://stormpath.com/blog/jwt-the-right-way/
    public static void Main()
    {           
        var header = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";
        var claims = "{\"sub\":\"1047986\",\"email\":\"jon.doe@eexample.com\",\"given_name\":\"John\",\"family_name\":\"Doe\",\"primarysid\":\"b521a2af99bfdc65e04010ac1d046ff5\",\"iss\":\"http://example.com\",\"aud\":\"myapp\",\"exp\":1460555281,\"nbf\":1457963281}";

        var b64header = Convert.ToBase64String(Encoding.UTF8.GetBytes(header))
            .Replace('+', '-')
            .Replace('/', '_')
            .Replace("=", "");
        var b64claims = Convert.ToBase64String(Encoding.UTF8.GetBytes(claims))
            .Replace('+', '-')
            .Replace('/', '_')
            .Replace("=", "");

        var payload = b64header + "." + b64claims;
        Console.WriteLine("JWT without sig:    " + payload);

        byte[] key = Convert.FromBase64String("mPorwQB8kMDNQeeYO35KOrMMFn6rFVmbIohBphJPnp4=");
        byte[] message = Encoding.UTF8.GetBytes(payload);

        string sig = Convert.ToBase64String(HashHMAC(key, message))
            .Replace('+', '-')
            .Replace('/', '_')
            .Replace("=", "");

        Console.WriteLine("JWT with signature: " + payload + "." + sig);        
    }

    private static byte[] HashHMAC(byte[] key, byte[] message)
    {
        var hash = new HMACSHA256(key);
        return hash.ComputeHash(message);
    }
}

Mã thông báo giải mã là phiên bản đảo ngược của mã ở trên. Để xác minh chữ ký, bạn sẽ cần phải giống nhau và so sánh phần chữ ký với chữ ký đã tính toán.

CẬP NHẬT: Đối với những người đang gặp khó khăn về cách mã hóa / giải mã urlsafe base64, vui lòng xem một câu hỏi SO khác , cũng như wiki và RFC


2
Câu trả lời rất hay. Mặc dù vì bạn hiển thị ký dựa trên HMAC ở đây, nên bạn có thể nhận biết được một số lỗ hổng nghiêm trọng trong các thư viện triển khai xác minh HMAC như được nêu chi tiết trên trang Auth0 tại đây: auth0.com/blog/2015/03/31/…
Sudhanshu Mishra

2
Tôi cảm thấy đây là câu trả lời tốt nhất. OP yêu cầu thông tin về JWT đặc biệt mà bài viết này địa chỉ bằng một ví dụ rõ ràng ..
webworm

13
Câu trả lời này giải thích và chứng minh làm thế nào để en mã một JWT khi câu hỏi là khá rõ ràng về de mã hóa. Đây có thể là một câu trả lời hay nhưng nó là một câu trả lời cho một câu hỏi hoàn toàn khác .
Deltics

2
@Deltics Tôi nghĩ rằng ngay cả bằng cấp khoa học máy tính cũng không cần thiết để viết lại thuật toán mã hóa để giải mã mã thông báo. Nếu bạn hiểu cách mã hóa - bạn hiểu cách giải mã
Đăng ký vào

31
Ý tưởng của một "câu trả lời" là để giải quyết một câu hỏi, không phải đặt ra một câu đố bằng cách mong đợi ai đó giải một số loại câu đố có ý định ngược lại. Bên cạnh giường, biết cách mã hóa không nhất thiết có nghĩa là sau đó bạn cũng biết cách giải mã vì điều này cũng có thể liên quan đến việc xử lý các mã thông báo của bên thứ ba và truy xuất khóa để xác minh chữ ký của họ, trái ngược với việc chỉ sử dụng một khóa để ký của riêng bạn. Trong mọi trường hợp, một câu trả lời mà không thực sự trả lời câu hỏi theo định nghĩa là không những " tốt hơn câu trả lời" khi so sánh với một mà làm , mà là quan sát mà tôi đã được đáp ứng.
Deltics
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.