• DotnetCore 使用Jwks验证JwtToken签名


    
    [Fact]
    public async Task VerfiyJwtTokenUseJwks()
    {
    
        var jwt = @"your jwt token";
    
    
    
        var wellKnownAddress = "http://your-openid-host/.well-known/openid-configuration";
        var httpClientFactory = this.ServiceProvier.GetRequiredService<IHttpClientFactory>();
        var httpClient = httpClientFactory.CreateClient();
    
        var response = await httpClient.GetAsync(wellKnownAddress);
        response.EnsureSuccessStatusCode();
    
        var json = await response.Content.ReadAsStringAsync();
        var jObj = (JObject)JsonConvert.DeserializeObject(json);
        var jwks_uri = jObj["jwks_uri"].ToString();
        Console.WriteLine($"Jwks_uri: {jwks_uri}");
    
    
        var keySet = await httpClient.GetStringAsync(jwks_uri);
        Console.WriteLine($"keySets: {keySet}");
    
        var ketSets = (JObject)JsonConvert.DeserializeObject(keySet);
        var keys = (JArray)ketSets["keys"];
    
        var jwtArray = jwt.Split('.');
        var headerObj = (JObject)JsonConvert.DeserializeObject(DecodeJwtToken(jwtArray[0]));
        Console.WriteLine($"Token Header: {headerObj}");
    
        var jwtSign = jwtArray[2];
    
        foreach (var key in keys)
        {
            var kid = headerObj["kid"];
            if (key["kid"].ToString() == kid.ToString())
            {
                var e = key["e"].ToString();
                var n = key["n"].ToString();
                using (var rsa = System.Security.Cryptography.RSA.Create())
                {
                    var rsaKeyInfo = new RSAParameters
                    {
                        Modulus = DecodeBase64ToByteArray(n),
                        Exponent = DecodeBase64ToByteArray(e)
                    };
    
                    rsa.ImportParameters(rsaKeyInfo);
                    var d = $"{jwtArray[0]}.{jwtArray[1]}";
    
                    var success = rsa.VerifyData(
                        Encoding.UTF8.GetBytes(d),
                        DecodeBase64ToByteArray(jwtSign), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    
                    Console.WriteLine($"verfiy: {success}");
    
                    var publicKeyPem = ExportPublicKey(rsa);
    
                    Console.WriteLine($"PublicKey PEM: 
    {publicKeyPem}");
    
                }
    
            }
    
        }
    }
    
    private string DecodeJwtToken(string base64Token)
    {
        var bytes = DecodeBase64ToByteArray(base64Token);
        var json = Encoding.UTF8.GetString(bytes);
        return json;
    }
    
    private byte[] DecodeBase64ToByteArray(string b64String)
    {
        var m = (b64String.Length % 4);
        if (m > 0)
        {
            if (m == 2)
            {
                b64String += "==";
            }
            else
            {
                b64String += "=";
            }
        }
        return Convert.FromBase64String(b64String.Replace("-", "+").Replace("_", "/"));
    }
    
    
    
    
    public static string ExportPublicKey(RSA csp)
    {
        StringWriter outputStream = new StringWriter();
        var parameters = csp.ExportParameters(false);
        using (var stream = new MemoryStream())
        {
            var writer = new BinaryWriter(stream);
            writer.Write((byte)0x30); // SEQUENCE
            using (var innerStream = new MemoryStream())
            {
                var innerWriter = new BinaryWriter(innerStream);
                innerWriter.Write((byte)0x30); // SEQUENCE
                EncodeLength(innerWriter, 13);
                innerWriter.Write((byte)0x06); // OBJECT IDENTIFIER
                var rsaEncryptionOid = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
                EncodeLength(innerWriter, rsaEncryptionOid.Length);
                innerWriter.Write(rsaEncryptionOid);
                innerWriter.Write((byte)0x05); // NULL
                EncodeLength(innerWriter, 0);
                innerWriter.Write((byte)0x03); // BIT STRING
                using (var bitStringStream = new MemoryStream())
                {
                    var bitStringWriter = new BinaryWriter(bitStringStream);
                    bitStringWriter.Write((byte)0x00); // # of unused bits
                    bitStringWriter.Write((byte)0x30); // SEQUENCE
                    using (var paramsStream = new MemoryStream())
                    {
                        var paramsWriter = new BinaryWriter(paramsStream);
                        EncodeIntegerBigEndian(paramsWriter, parameters.Modulus); // Modulus
                        EncodeIntegerBigEndian(paramsWriter, parameters.Exponent); // Exponent
                        var paramsLength = (int)paramsStream.Length;
                        EncodeLength(bitStringWriter, paramsLength);
                        bitStringWriter.Write(paramsStream.GetBuffer(), 0, paramsLength);
                    }
                    var bitStringLength = (int)bitStringStream.Length;
                    EncodeLength(innerWriter, bitStringLength);
                    innerWriter.Write(bitStringStream.GetBuffer(), 0, bitStringLength);
                }
                var length = (int)innerStream.Length;
                EncodeLength(writer, length);
                writer.Write(innerStream.GetBuffer(), 0, length);
            }
    
            var base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray();
            // WriteLine terminates with 
    , we want only 
    
            outputStream.Write("-----BEGIN PUBLIC KEY-----
    ");
            for (var i = 0; i < base64.Length; i += 64)
            {
                outputStream.Write(base64, i, Math.Min(64, base64.Length - i));
                outputStream.Write("
    ");
            }
            outputStream.Write("-----END PUBLIC KEY-----");
        }
    
        return outputStream.ToString();
    }
    
    
    private static void EncodeLength(BinaryWriter stream, int length)
    {
        if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative");
        if (length < 0x80)
        {
            // Short form
            stream.Write((byte)length);
        }
        else
        {
            // Long form
            var temp = length;
            var bytesRequired = 0;
            while (temp > 0)
            {
                temp >>= 8;
                bytesRequired++;
            }
            stream.Write((byte)(bytesRequired | 0x80));
            for (var i = bytesRequired - 1; i >= 0; i--)
            {
                stream.Write((byte)(length >> (8 * i) & 0xff));
            }
        }
    }
    
    private static void EncodeIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true)
    {
        stream.Write((byte)0x02); // INTEGER
        var prefixZeros = 0;
        for (var i = 0; i < value.Length; i++)
        {
            if (value[i] != 0) break;
            prefixZeros++;
        }
        if (value.Length - prefixZeros == 0)
        {
            EncodeLength(stream, 1);
            stream.Write((byte)0);
        }
        else
        {
            if (forceUnsigned && value[prefixZeros] > 0x7f)
            {
                // Add a prefix zero to force unsigned if the MSB is 1
                EncodeLength(stream, value.Length - prefixZeros + 1);
                stream.Write((byte)0);
            }
            else
            {
                EncodeLength(stream, value.Length - prefixZeros);
            }
            for (var i = prefixZeros; i < value.Length; i++)
            {
                stream.Write(value[i]);
            }
        }
    }
    
    
  • 相关阅读:
    Python mutilprocessing Processing 父子进程共享文件对象?
    BZOJ4836: [Lydsy1704月赛]二元运算
    博弈论刷题记录
    manacher(无讲解)
    UOJ_407_【IOI2018】狼人
    BZOJ_3935_Rbtree
    dsu on tree(无讲解)
    BZOJ_3744_Gty的妹子序列
    后缀数组(无讲解)
    虚树(无讲解)
  • 原文地址:https://www.cnblogs.com/byxxw/p/11243772.html
Copyright © 2020-2023  润新知