web-dev-qa-db-fra.com

Comment vérifier un JWT signé asymétriquement dans un noyau dotnet?

J'ai trouvé des exemples de signature asymétrique dans .NET FW et des exemples de signature symétrique dans .NET Core, mais je ne peux pas comprendre comment vérifier asymétriquement un JWT dans .NET Core. Étant donné une URL vers un ensemble JWK ou une clé publique, comment puis-je vérifier un jeton dans .NET Core?

4
twinlakes

J'ai fini par implémenter la spécification OpenID Connect Discovery , qui vous permet de publier le point de terminaison du jeton et le point de terminaison du jeu de clés dans un format standard. Ensuite, je pourrais utiliser la méthode d'extension AddJwtBearer()AuthenticationBuilder pour mettre en cache automatiquement le jeu de clés, vérifier les jetons et remplir le ClaimsPrincipal.

Pour écrire votre propre service de jeton qui implémente le protocole OpenID Connect Discovery, vous devrez:

  • Implémenter une route /keys qui sert un Microsoft.IdentityModel.Tokens.JsonWebKeySet objet dérivé de vos certificats pfx.

    JsonWebKeySet GetJwksFromCertificates(IEnumerable<X509Certificate2> certificates)
    {
        var jwks = new JsonWebKeySet();
    
        foreach (var certificate in certificates)
        {
            var rsaParameters = ((RSA)certificate.PublicKey.Key).ExportParameters(false);
    
            var jwk = new JsonWebKey
            {
                // https://tools.ietf.org/html/rfc7517#section-4
                Kty = certificate.PublicKey.Key.KeyExchangeAlgorithm,
                Use = "sig",
                Kid = certificate.Thumbprint,
                X5t = certificate.Thumbprint,
    
                // https://tools.ietf.org/html/rfc7517#appendix-B
                N = Convert.ToBase64String(rsaParameters.Modulus),
                E = Convert.ToBase64String(rsaParameters.Exponent),
            };
    
            jwks.Keys.Add(jwk);
        }
    
         return jwks;
    }
    
  • Implémenter une route /not-yet-implemented qui renvoie 501 Not Implemented.
  • Implémenter une route /.well-known/openid-configuration qui sert un Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration objet.
    OpenIdConnectConfiguration GetOpenIdConnectConfiguration(string issuer) {
        var configuration = new OpenIdConnectConfiguration
        {
            Issuer = issuer,
            TokenEndpoint = issuer + "/token",
            AuthorizationEndpoint = issuer + "/not-yet-implemented",
            JwksUri = issuer + "/keys",
        };
        configuration.GrantTypesSupported.Add(grantType);
        return configuration;
    }
    
  • Implémenter une route /token qui utilise votre logique spécifique à l'application pour authentifier l'utilisateur et générer un ClaimsIdentity, puis crée un System.IdentityModel.Tokens.Jwt.JwtSecurityToken en utilisant un JwtSecurityTokenHandler.

    JwtSecurityToken CreateJwt(
        string issuer,
        TimeSpan lifetime,
        ClaimsIdentity claimsIdentity,
        X509Certificate2 signingCertificate)
    {
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Issuer = issuer,
            Expires = DateTime.UtcNow.Add(lifetime),
            NotBefore = DateTime.UtcNow,
            Subject = claimsIdentity,
            SigningCredentials = new X509SigningCredentials(signingCertificate),
        };
    
        return new JwtSecurityTokenHandler().CreateJwtSecurityToken(tokenDescriptor);
    }
    

Je vous encourage également à implémenter le OAuth client_credentials accorder des flux pour votre /token route.

1
twinlakes