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 ...
随机推荐
- 硬核干货 | C++后台开发学习路线
2020秋招提前批 C/C++相关开发 拿到腾讯.华为等offer 学习路线及时间安排 推荐时间为4个月,包括四部分:语言,计算机基础知识,项目基础知识,项目实践. 语言 推荐学习1个月 学习方针:视 ...
- 基于光盘配置yum源
#开启自动挂载服务 systemctl start autofs #设置开机自动挂载 systemctl enable autofs #光盘自动挂载路径/misc/cd “包含repoda ...
- sql查询如何将A表数据name字段对应B表name字段得到对应的B表id主键然后添加A到表usel_id中
1.写这个的原因 最近在写公司项目的时候一个功能很是让我头疼如标题看到的一样,平时我们一般都只负责数据表的查询或者连表查询某一个字段和A表字段一起显示出来. 但是添加到A表还是头一次,第一天想了很久都 ...
- js image to base64 摘录
//传入图片路径,返回base64 //用处,由于在新增时,使用的是base64的格式,为了统一,在编辑时,也将图片转为base64,以便于统一处理 /* 使用: 因为图像处理存在一定的延时,所以通过 ...
- 巨杉数据库SequoiaDB】巨杉Tech | SequoiaDB 分布式事务实现原理简介
1 分布式事务背景 随着分布式数据库技术的发展越来越成熟,业内对于分布式数据库的要求也由曾经只用满足解决海量数据的存储和读取这类边缘业务向核心交易业务转变.分布式数据库如果要满足核心账务类交易需求,则 ...
- HTML与W3C
HTML:超文本标记语言 超文本包括:文字.图片.音频.视频.动画等 流程:写好HTML代码后通过浏览器(自动编译HTML代码)展现出效果 HTML优点: 世界知名浏览器厂商对HTML5的支持 微软 ...
- 【android】Parcelable的相关技术总结
关于Parcelable的相关知识学习 进行Android开发的时候,无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然 ...
- py 二级习题(turtle)
用turtle画一个正方形 import turtle turtle.penup() turtle.goto(-100,-100) turtle.pendown() turtle.begin_fill ...
- 牛客练习赛53 C题bitset
题目链接https://ac.nowcoder.com/acm/contest/1114/C #include<bits/stdc++.h> using namespace std; #d ...
- 牛客练习赛53 B题调和级数
https://ac.nowcoder.com/acm/contest/1114/B 这题时间卡的比较死,多了一个快速幂的logn就过不了这题. #include<bits/stdc++.h&g ...