Decodificación y verificación de token JWT utilizando el Sistema.IdentityModel.Token.Jwt


He estado usando la biblioteca JWT para decodificar un token web Json, y me gustaría cambiar a la implementación oficial de JWT de Microsoft, System.IdentityModel.Token.Jwt .

La documentación es muy escasa, así que estoy teniendo dificultades para averiguar cómo lograr lo que he estado haciendo con la biblioteca JWT. Con la biblioteca JWT, hay un método de decodificación que toma el JWT codificado base64 y lo convierte en JSON que luego se puede deserializar. Me gustaría hacer algo similar usando el sistema.IdentityModel.Token.Jwt, pero después de una buena cantidad de excavación, no puede averiguar cómo.

Por si sirve de algo, estoy leyendo el token JWT de una cookie, para usarlo con el marco de identidad de Google.

Cualquier ayuda sería apreciada.

 78
Author: w.brian, 2013-09-08

2 answers

Dentro del paquete hay una clase llamada JwtSecurityTokenHandler que deriva de System.IdentityModel.Tokens.SecurityTokenHandler. En WIF esta es la clase principal para deserializar y serializar tokens de seguridad.

La clase tiene un método ReadToken(String) que tomará su cadena JWT codificada en base64 y devuelve un SecurityToken que representa el JWT.

El SecurityTokenHandler también tiene un método ValidateToken(SecurityToken) que toma su SecurityToken y crea un ReadOnlyCollection<ClaimsIdentity>. Por lo general, para JWT, esto contendrá un único objeto ClaimsIdentity que tiene un conjunto de afirmaciones que representan las propiedades del JWT original.

JwtSecurityTokenHandler define algunas sobrecargas adicionales para ValidateToken, en particular, tiene una sobrecarga ClaimsPrincipal ValidateToken(JwtSecurityToken, TokenValidationParameters). El argumento TokenValidationParameters le permite especificar el certificado de firma de token (como una lista de X509SecurityTokens). También tiene una sobrecarga que toma el JWT como un string en lugar de un SecurityToken.

El código para hacer esto es bastante complicado, pero se puede encontrar en Global.asax.cx code (TokenValidationHandler class) en el ejemplo de desarrollador llamado " ADAL - Native App to REST service-Authentication con ACS vía Browser Dialog", ubicado en

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

Alternativamente, la clase JwtSecurityToken tiene métodos adicionales que no están en la clase base SecurityToken, como una propiedad Claims que obtiene las reclamaciones contenidas sin pasar por la colección ClaimsIdentity. También tiene una propiedad Payload que devuelve un objeto JwtPayload que le permite obtener el JSON sin procesar del token. Depende de su escenario que se acercan más adecuado.

La documentación general (es decir, no específica de JWT) para la clase SecurityTokenHandler está en

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

Dependiendo de su aplicación, puede configurar el controlador JWT en la canalización WIF exactamente como cualquier otro controlador.

Hay 3 muestras de ella en uso en diferentes tipos de aplicación at

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

Probablemente, uno satisfará sus necesidades o al menos será adaptable a ellas.

 116
Author: Mike Goodwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-20 15:56:42

Me pregunto por qué usar algunas bibliotecas para la decodificación y verificación de tokens JWT.

El token JWT codificado se puede crear usando después del pseudocódigo

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

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

var encodedJWT = payload + "." + signature;

Es muy fácil prescindir de una biblioteca específica. Usando el siguiente código:

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\":\"[email protected]\",\"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);
    }
}

La decodificación del token es una versión invertida del código above.To verifique la firma que necesitará para la misma y compare la parte de firma con la firma calculada.

ACTUALIZACIÓN: Para aquellos cómo son luchando cómo hacer base64 urlsafe codificación / decodificación por favor ver otro ASÍ pregunta , y también wiki y RFC

 17
Author: Regfor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-24 17:48:15