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: \r\n{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 \r\n, we want only \n
        outputStream.Write("-----BEGIN PUBLIC KEY-----\n");
        for (var i = 0; i < base64.Length; i += 64)
        {
            outputStream.Write(base64, i, Math.Min(64, base64.Length - i));
            outputStream.Write("\n");
        }
        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]);
        }
    }
}
DotnetCore 使用Jwks验证JwtToken签名的更多相关文章
- OpenSSL库验证PKCS7签名
		使用Crypto库签名和验证签名请参考Crypto库实现PKCS7签名与签名验证,可以使用OpenSSL库验证Crypto签名,OpenSSL验证签名可使用简单的代码描述如下: //signature ... 
- ubuntu16.04 apt-get update出错:由于没有公钥,无法验证下列签名
		问题: W: 校验数字签名时出错.此仓库未被更新,所以仍然使用此前的索引文件.GPG 错误:https://packagecloud.io/github/git-lfs/ubuntu xenial I ... 
- 由于没有公钥,无法验证下列签名 Ubuntu
		问题:执行 apt-get update 时错误 W: GPG 错误:https://apt.dockerproject.org ubuntu-trusty InRelease: 由于没有公钥,无法验 ... 
- 树莓派 Learning 002 装机后的必要操作 --- 04 添加软件源 之 添加公钥 --- 解决“由于没有公钥,无法验证下列签名”问题
		树莓派 装机后的必要操作 - 添加软件源 解决 添加公钥 时会遇到的问题 当你添加完Debian的软件源后,在终端中执行sudo apt-get update时,会出现下面的错误:(这里我添加了3个软 ... 
- sudo apt-get update 没有公钥,无法验证下列签名
		在更新系统源后,输入sudo apt-get update之后出现提示: W: GPG 错误:http://archive.ubuntukylin.com:10006 xenial InRelease ... 
- ”W: GPG 错误:http://ppa.launchpad.net lucid Release: 由于没有公钥,无法验证下列签名:“的问题
		在安装更新时,即在运行,命令行sudo apt-get update 或者运行更新管理器的时候,出现如下错误: W: GPG 错误:http://ppa.launchpad.net lucid Rel ... 
- 更新linux时候提示“由于没有公钥,无法验证下列签名".
		本文链接:https://blog.csdn.net/loovejava/article/details/21837935 新安装的Ubuntu在使用sudo apt-get update更新源码的时 ... 
- 乌班图14更新软件提示错误:https://mirrors.aliyun.com kubernetes-xenial InRelease: 由于没有公钥,无法验证下列签名: NO_PUBKEY 6A030B21BA07F4FB
		提示如下 获取: https://mirrors.aliyun.com kubernetes-xenial InRelease 忽略 https://mirrors.aliyun.com kubern ... 
- .net mvc 微信公众号 验证微信签名
		官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN ... 
随机推荐
- Java后端API调用身份验证的思考
			在如今信息泛滥的数字时代中对产品安全性的要求越来越高了,就比如说今天要讨论的Java后端API调用的安全性,在你提供服务的接口中一定要保证调用方身份的有效性和合法性,不能让非法的用户进行调用,避免数据 ... 
- Android_ExpandableListView
			实现效果: 类似于QQ联系人列表 相关属性: android:childDivider:指定各组内子类表项之间的分隔条,图片不会完全显示, 分离子列表项的是一条直线 android:childIndi ... 
- H5_0020:判断安卓苹果平台
			var u = navigator.userAgent, app = navigator.appVersion; var isAndroid = u.indexOf('Android') > - ... 
- mac 安装Kafka
			1. 安装zookeeper brew install zookeeper 默认安装位置 启动文件: /usr/local/Cellar/zookeeper/3.4.10/bin/ 配置文件: /us ... 
- 在Scala中免费验证
			优锐课带你详细了解如何在Scala中实施免费的monad验证.抽丝剥茧,细说架构那些事! 由于业务数据的复杂性,已经在数据验证上花费了很多精力.在Scala中,提出了使用应用程序进行验证的方法,并被广 ... 
- [Agc081F/At2699] Flip and Rectangles - 单调栈,结论
			[Agc081F/At2699] 给出一个拥有 \(H\times W\) 个格子的棋盘,每个格子的颜色为黑色或白色. Snuke 可以进行任意次下列操作: 选择棋盘中的一行或一列,将这一行或一列的颜 ... 
- Linux - mysql 异常: ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists
			问题描述 ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists 解决方案 删除:/var/lock/su ... 
- (转)git rebase 命令
			转自:http://blog.csdn.net/hudashi/article/details/7664631/ 原文: http://gitbook.liuhui998.com/4_2.html 一 ... 
- jsp报错java.io.IOException: Stream closed
			在使用jsp的时候莫名其妙的抛出了这个异常,经过反复检查 去掉了网友们说的jsp使用流未关闭,以及tomcat版本冲突等原因,最后发现是书写格式的原因. 当时使用的代码如下 <jsp:inclu ... 
- AttributeError: 'SQLAlchemy' object has no attribute 'Foreignkey'
			在学习<Flask Web开发----基于Python的Web应用开发实战>的过程中,调试程序,如下图,运行报错: AttributeError: 'SQLAlchemy' object ... 
