我的 asp.net core (3.1) webapi 也遇到了同样的问题,它使用 AWS Cognito 进行身份验证,使用的方法如下所述:
https://medium.com/@marcio_30193/jwt-machine-to-machine-usando-aws-cognito-and-c-b1fab0524712 https://medium.com/@marcio_30193/jwt-machine-to-machine-usando-aws-cognito-and-c-b1fab0524712
这导致了类似于 @Punit 的公共代码块,如下所示;
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
// Get JsonWebKeySet from AWS
var json = new WebClient().DownloadString($"{parameters.ValidIssuer}/.well-known/jwks.json");
// Deserialize the result
return JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
}
这段代码的问题在于,在 ASP.NET Core 中,这将导致线程池饥饿。
DownloadString 方法是同步的,但它内部执行 .Result 调用,导致线程阻塞,当请求激增时,这可能会导致线程池饥饿。
我使用 Ben.Blocking 检测器发现了这个阻塞调用 - 非常酷https://github.com/benaadams/Ben.BlockingDetector https://github.com/benaadams/Ben.BlockingDetector
https://www.nuget.org/packages/Ben.BlockingDetector/ https://www.nuget.org/packages/Ben.BlockingDetector/
那么如何解决呢?
我尝试过,但我认为在代表内部不可能解决。
IssuerSigningKeyResolver 是同步委托,无法接受异步响应。因此,即使 WebClient 有 DownloadStringAsyncTask,它也会将响应放入 IssuerSigningKeyResolver 不会接受的任务中。
简单的解决方案是跳出框框(或委托)思考。
使用 AWS Cognito,请求的数据位于如下 URL;
https://cognito-idp.{region}.amazonaws.com/{user-pool-id}/.well-known/jwks.json
这将返回 JsonWebKeySet 对象的集合,该对象表示一组加密密钥。
我已与 AWS 确认,该池的数据不应更改,因为当前池上没有密钥轮换策略..所以..
解决方案是在委托方法之外请求此数据并将其传入。
这样做有两个好处;
- 它解决了问题
- 它更有效率。
这个委托方法在每个请求上执行,因此我们每次都调用这个 .well-known/jwks URL,并且响应(每个环境)永远不会改变!
我的代码如下所示;
var issuingKeys = GetIssuerSigningKey(AuthSettings.CognitoUserPoolUrl);
services.AddAuthentication(options =>
...
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
return issuingKeys;
}
...
);
private static IList<JsonWebKey> GetIssuerSigningKey(string cognitioUserPoolUrl)
{
var json = new WebClient().DownloadString($"{cognitioUserPoolUrl}/.well-known/jwks.json");
return JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
}
就我使用 AWS Cognito 的情况而言,这些数据存在更改的风险。
我的解决方案是启动一个带有 30 秒或 60 秒计时器的后台线程,然后在该时间间隔刷新静态 IssueKey。
如果确实发生变化,该网站将出现最多 30 秒的小故障,然后继续。
在 @Punit 的示例中,他从 appSettings 获取 100% 不会更改的签名密钥,因此只需通过获取您的
在设置代码中的委托函数之外签名并返回它。
解决此问题的唯一其他方法是将 IssuerSigningKeyResolver 转换为 IssuerSigningKeyResolverAsync(可能在更高版本的 .Net Core 中)。
(我们目前在 Lambda 中运行代码,目前仅支持 .net 3.1,因此我们尚未尝试更新版本)
希望这可以帮助。