Декодування та перевірка маркера JWT за допомогою System.IdentityModel.Tokens.Jwt


101

Я використовую бібліотеку JWT для декодування веб-маркера Json і хотів би перейти на офіційну реалізацію JWT від Microsoft, System.IdentityModel.Tokens.Jwt .

Документація дуже скупа, тому мені важко зрозуміти, як досягти того, що я робив із бібліотекою JWT. У бібліотеці JWT існує метод Decode, який приймає закодований в base64 JWT і перетворює його в JSON, який потім можна десеріалізувати. Я хотів би зробити щось подібне, використовуючи System.IdentityModel.Tokens.Jwt, але після значної кількості копань не можу зрозуміти, як.

Для того, що це варто, я читаю маркер JWT із файлу cookie для використання з системою ідентифікації Google.

Будь-яка допомога буде вдячна.



Ось практична відповідь про те, як отримати сертифікати Google і перевірити маркер - stackoverflow.com/questions/29757140/…
rothschild86

Відповіді:


147

У пакеті є клас, JwtSecurityTokenHandlerякий називається і походить від System.IdentityModel.Tokens.SecurityTokenHandler. У WIF це основний клас для десериалізації та серіалізації маркерів безпеки.

Клас має ReadToken(String)метод, який прийме кодований рядок JWT base64 і повертає a, SecurityTokenякий представляє JWT.

SecurityTokenHandlerТакож є ValidateToken(SecurityToken)метод , який приймає ваш SecurityTokenі створює ReadOnlyCollection<ClaimsIdentity>. Зазвичай для JWT він буде містити один ClaimsIdentityоб'єкт, який має набір вимог, що представляють властивості вихідного JWT.

JwtSecurityTokenHandlerвизначає деякі додаткові перевантаження ValidateToken, зокрема, він має ClaimsPrincipal ValidateToken(JwtSecurityToken, TokenValidationParameters)перевантаження. TokenValidationParametersАргумент дозволяє вказати сертифікат маркерів підпису (у вигляді списку X509SecurityTokens). Він також має перевантаження, яке сприймає JWT, stringа не як SecurityToken.

Код для цього досить складний, але його можна знайти в коді ( TokenValidationHandlerкласі) Global.asax.cx у зразку розробника під назвою "ADAL - Рідне додаток до служби REST - Аутентифікація за допомогою ACS через діалогове вікно браузера", розташоване за адресою

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

Крім того, JwtSecurityTokenклас має додаткові методи, які не відносяться до базового SecurityTokenкласу, такі як Claimsвластивість, яка отримує вміщені претензії, не проходячи ClaimsIdentityколекцію. Він також має Payloadвластивість, що повертає JwtPayloadоб'єкт, який дозволяє отримати вихідний JSON маркера. Це залежить від вашого сценарію, який підхід до нього є найбільш доцільним.

Загальна (тобто не специфічна для JWT) документація до SecurityTokenHandlerкласу знаходиться на

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

Залежно від вашої програми, ви можете налаштувати обробник JWT у конвеєр WIF точно так само, як і будь-який інший обробник.

Існує 3 його зразки, які використовуються для різних типів застосування на

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

Можливо, один задовольнить ваші потреби або, принаймні, буде адаптований до них.


3
Я дуже ціную вашу відповідь. Отже, як тільки я отримаю ClaimsIdentity, як мені перевірити його на основі відкритого ключа? Зокрема, я намагаюсь перевірити набір інструментів Google для ідентифікації JWT щодо їх відкритого ключа ( gstatic.com/authtoolkit/cert/gitkit_cert.pem )
w.brian

4
Оновив свою відповідь - я не міг помістити повне джерело для цього, але я вказав вам напрямок відповідного зразка розробника. Сподіваюся, це допомагає.
Mike Goodwin

4
@ w.brian - я намагаюся зробити те саме. У мене є маркер, який я можу декодувати, і відкритий ключ, який я хочу перевірити, але навіть дивлячись на ці зразки, я намагаюся побачити, як я це роблю. Чи є у вас вказівки на те, який код вам насправді допоміг? Дякую.
Баргуаст,

26

Мені просто цікаво, навіщо взагалі використовувати деякі бібліотеки для декодування та перевірки маркерів JWT.

Кодований маркер JWT можна створити, використовуючи наступний псевдокод

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

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

var encodedJWT = payload + "." + signature;

Це дуже легко обійтися без будь-якої конкретної бібліотеки. Використовуючи такий код:

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

Декодування маркера - це зворотна версія коду вище. Щоб перевірити підпис, вам знадобиться той самий і порівняти частину підпису з обчисленим підписом.

ОНОВЛЕННЯ: Для тих, хто бореться з тим, як зробити кодування / декодування urlsafe base64, див. Ще одне запитання SO , а також wiki та RFC


2
Приємна відповідь. Хоча, оскільки ви показуєте тут підписання на основі HMAC, може мати сенс знати про деякі критичні вразливості в бібліотеках, що реалізують перевірку HMAC, як це докладно викладено на сайті Auth0 тут: auth0.com/blog/2015/03/31/…
Sudhanshu Mishra

2
Я вважаю, що це найкраща відповідь. Оператор запитував інформацію про JWT, конкретно до якої ця стаття звертається на наочному прикладі.
webworm

13
Ця відповідь пояснює і показує , як ан коду JWT , коли мова йде про абсолютно ясно де кодуванні. Це може бути приємною відповіддю, але це відповідь на зовсім інше питання .
Deltics

2
@Deltics Я думаю, що навіть ступінь інформатики не потрібен для переписування алгоритму кодування для декодування токена. Якщо ви розумієте, як кодувати - ви розумієте, як декодувати
Regfor

31
Ідея "відповіді" полягає в тому, щоб звернутися до питання, а не задавати головоломку, очікуючи, що хтось вирішить якусь загадку із зворотним наміром. Помішки, знання того, як кодувати, не обов’язково означає, що ви тоді також знаєте, як декодувати, оскільки це може також передбачати роботу зі сторонніми маркерами та отримання ключів для перевірки їх підписів, на відміну від простого використання ключа для підпису власного. У будь-якому випадку, відповідь , який ніяк НЕ на насправді відповісти на цей питання , за визначенням, НЕ « краще » відповідь у порівнянні з тією , що робить , що спостереження , до якого я відповідав.
Deltics
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.