IssuerSigningKeyResolver 调用异步方法

2024-05-08

我们使用 IssuerSigningKeyResolver,它是 Microsoft.IdentityModel.Tokens 的一部分,用于令牌验证并接受非异步委托。我们调用一个异步方法,这将导致阻塞调用,因此想知道使用它的正确方法是什么。

IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
                {
                    return configurationManager.GetConfigurationAsync().ConfigureAwait(false).GetAwaiter().GetResult().SigningKeys;
                }

我的 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 确认,该池的数据不应更改,因为当前池上没有密钥轮换策略..所以..

解决方案是在委托方法之外请求此数据并将其传入。

这样做有两个好处;

  1. 它解决了问题
  2. 它更有效率。

这个委托方法在每个请求上执行,因此我们每次都调用这个 .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,因此我们尚未尝试更新版本)

希望这可以帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IssuerSigningKeyResolver 调用异步方法 的相关文章

  • 用于代数简化和求解的 C# 库 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 网络上有很多代数求解器和简化器 例如 algebra com 上不错的代数求解器和简化器 然而 我正在
  • 使用 std::packaged_task/std::exception_ptr 时,线程清理程序报告数据争用

    我遇到了线程清理程序 TSan 的一些问题 抱怨某些生产代码中的数据争用 其中 std packaged task 通过将它们包装在 std function 中而移交给调度程序线程 对于这个问题 我简化了它在生产中的作用 同时触发 TSa
  • 未提供参数时如何指定 C# System.Commandline 行为?

    在我的控制台应用程序中 当未提供控制台参数时 将执行我指定列表 在本例中为参数 3 的任何处理程序 调用该处理程序时 布尔参数设置为 false 但对我来说 根本不调用它更有意义 如何防止这种情况发生并显示帮助文本 using System
  • 注销租约抛出 InvalidOperationException

    我有一个使用插件的应用程序 我在另一个应用程序域中加载插件 我使用 RemoteHandle 类http www pocketsilicon com post Things That Make My Life Hell Part 1 App
  • 确保 StreamReader 不会挂起等待数据

    下面的代码读取从 tcp 客户端流读取的所有内容 并且在下一次迭代中它将仅位于 Read 上 我假设正在等待数据 我如何确保它不会在没有任何内容可供读取时返回 我是否必须设置低超时 并在失败时响应异常 或者有更好的办法吗 TcpClient
  • MVC 在布局代码之前执行视图代码并破坏我的脚本顺序

    我正在尝试将所有 javascript 包含内容移至页面底部 我正在将 MVC 与 Razor 一起使用 我编写了一个辅助方法来注册脚本 它按注册顺序保留脚本 并排除重复的内容 Html RegisterScript scripts som
  • 错误:表达式不产生值

    我尝试将以下 C 代码转换为 VB NET 但在编译代码时出现 表达式不产生值 错误 C Code return Fluently Configure Mappings m gt m FluentMappings AddFromAssemb
  • 在 C 中匹配二进制模式

    我目前正在开发一个 C 程序 需要解析一些定制的数据结构 幸运的是我知道它们是如何构造的 但是我不确定如何在 C 中实现我的解析器 每个结构的长度都是 32 位 并且每个结构都可以通过其二进制签名来识别 举个例子 有两个我感兴趣的特定结构
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 为什么调用非 const 成员函数而不是 const 成员函数?

    为了我的目的 我尝试包装一些类似于 Qt 共享数据指针的东西 经过测试 我发现当应该调用 const 函数时 会选择它的非 const 版本 我正在使用 C 0x 选项进行编译 这是一个最小的代码 struct Data int x con
  • Qt - ubuntu中的串口名称

    我在 Ubuntu 上查找串行端口名称时遇到问题 如您所知 为了在 Windows 上读取串口 我们可以使用以下代码 serial gt setPortName com3 但是当我在 Ubuntu 上编译这段代码时 我无法使用这段代码 se
  • C#:帮助理解 UML 类图中的 <>

    我目前正在做一个项目 我们必须从 UML 图编写代码 我了解 UML 类图的剖析 但我无法理解什么 lt
  • 如何设置 log4net 每天将我的文件记录到不同的文件夹中?

    我想将每天的所有日志保存在名为 YYYYMMdd 的文件夹中 log4net 应该根据系统日期时间处理创建新文件夹 我如何设置它 我想将一天中的所有日志保存到 n 个 1MB 的文件中 我不想重写旧文件 但想真正拥有一天中的所有日志 我该如
  • 使用 C# 读取 Soap 消息

  • 方法优化 - C#

    我开发了一种方法 允许我通过参数传入表 字符串 列数组 字符串 和值数组 对象 然后使用这些参数创建参数化查询 虽然它工作得很好 但代码的长度以及多个 for 循环散发出一种代码味道 特别是我觉得我用来在列和值之间插入逗号的方法可以用不同的
  • C++ 条件编译

    我有以下代码片段 ifdef DO LOG define log p record p else define log p endif void record char data 现在如果我打电话log hello world 在我的代码中
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData
  • 从列表中选择项目以求和

    我有一个包含数值的项目列表 我需要使用这些项目求和 我需要你的帮助来构建这样的算法 下面是一个用 C 编写的示例 描述了我的问题 int sum 21 List

随机推荐