如何使用 IHttpClientFactory 刷新令牌

2024-02-04

我使用 IHttpClientFactory 使用 Net Core 2.2 发送请求并从两个外部 API 接收 HTTP 响应。

我正在寻找一个好的策略来使用已存储在 appsettings.json 中的刷新令牌来获取新的访问令牌。当当前请求返回 403 或 401 错误时,需要请求新的访问令牌。获得新的访问令牌和刷新令牌后,需要使用新值更新 appsettings.json 以便在后续请求中使用。

我使用两个客户端向两个不同的 API 发送请求,但只有其中一个使用令牌身份验证机制。

我已经实现了一些简单有效的方法,但我正在寻找一种更优雅的解决方案,可以在当前令牌过期时动态更新标头:

我已在 Startup.ConfigureServices 方法中注册了 IHttpClientFactory,如下所示:

services.AddHttpClient();

注册后,我将在两种不同的方法中使用它来调用两个不同的 API,第一种方法是:

   public async Task<AirCallRequest> GetInformationAsync(AirCallModel model)
    {
        try
        {


            CandidateResults modelCandidateResult = null;

            var request = new HttpRequestMessage(HttpMethod.Get,
            "https://*******/v2/*****");
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _appSettings.Value.Token);


            var clientJAAPI = _httpClientFactory.CreateClient();
            var responseclientJAAPI = await clientJAAPI.SendAsync(request);


            if (responseclientJAAPI.IsSuccessStatusCode)
            {
                modelCandidateResult = await responseclientJAAPI.Content
                   .ReadAsAsync<CandidateResults>();

                ....
            }


            if ((responseclientJAAPI .StatusCode.ToString() == "Unauthorized")
            {                    

                await RefreshAccessToken();

               //Calls recursively this method again
                return await GetInformationAsync(model);

            }

            return null;
        }
        catch (Exception e)
        {
            return null;

        }

    }

刷新令牌方法如下所示:

private async Task RefreshAccessToken()
    {


        var valuesRequest = new List<KeyValuePair<string, string>>();
        valuesRequest.Add(new KeyValuePair<string, string>("client_id", "*****"));
        valuesRequest.Add(new KeyValuePair<string, string>("client_secret","****"));
        valuesRequest.Add(new KeyValuePair<string, string>("grant_type", "refresh_token"));
        valuesRequest.Add(new KeyValuePair<string, string>("refresh_token", "*****"));


        RefreshTokenResponse refreshTokenResponse = null;

        var request = new HttpRequestMessage(HttpMethod.Post,
        "https://*****/connect/token");

        request.Content = new FormUrlEncodedContent(valuesRequest);

        var clientJAAPI = _httpClientFactory.CreateClient();
        var responseclientJAAPI = await clientJAAPI.SendAsync(request);

        if (responseclientJAAPI.IsSuccessStatusCode)
        {
            refreshTokenResponse = await responseclientJAAPI.Content.ReadAsAsync<RefreshTokenResponse>();

            //this updates the POCO object representing the configuration but not the appsettings.json :
            _appSettings.Value.Token = refreshTokenResponse.access_token;

        }

    }

请注意,我正在更新表示配置的 POCO 对象,而不是 appsettings.json,因此新值存储在内存中。我想更新 appsettings.json 以用于后续请求。

如果建议的解决方案需要在 Startup.ConfigureService 中定义 Httpclient 的主要设置,则需要允许创建 HttpClient 的不同实例,因为其中一个 HttpClient 实例(在另一种方法中使用来调用第二个 API)不会不需要令牌来发送请求。


看起来你需要委托处理程序 https://www.stevejgordon.co.uk/httpclientfactory-aspnetcore-outgoing-request-middleware-pipeline-delegatinghandlers。简而言之,您可以“拦截”您的 http 请求并添加授权标头,然后尝试执行它,如果令牌无效,则刷新令牌并重试一次。就像是:

public class AuthenticationDelegatingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var token = await GetTokenAsync();
        request.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, token.AccessToken);
        var response = await base.SendAsync(request, cancellationToken);

        if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
        {
            token = await RefreshTokenAsync();
            request.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, token.AccessToken);
            response = await base.SendAsync(request, cancellationToken);
        }

        return response;
    }
}

您可以在 Startup.cs 中注册此委托处理程序,如下所示:

services.AddTransient<AuthenticationDelegatingHandler>();
services.AddHttpClient("MySecuredClient", client =>
    {
        client.BaseAddress = new Uri("https://baseUrl.com/");
    })
    .AddHttpMessageHandler<AuthenticationDelegatingHandler>();

并像这样使用:

var securedClient = _httpClientFactory.CreateClient("MySecuredClient");
securedClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "v2/relativeUrl"));

关于在 appsetting.json 中存储刷新令牌。我认为这不是一个好主意,因为刷新令牌没有过期时间。如果您第一次可以使用凭据获取新令牌,请使用它,然后将刷新令牌存储在内存中以供进一步刷新。

Here https://github.com/gao-artur/AuthenticationHandler您可以了解我如何管理客户端凭据令牌刷新并尝试使其适合您的场景。


Update:

Here https://identitymodel.readthedocs.io/en/latest/aspnetcore/overview.html您可以找到相同的想法,但由专业人员实施并可在nuget https://www.nuget.org/packages/IdentityModel.AspNetCore。使用方法非常简单:

services.AddAccessTokenManagement(options =>
{
    options.Client.Clients.Add("identityserver", new ClientCredentialsTokenRequest
    {
        Address = "https://demo.identityserver.io/connect/token",
        ClientId = "m2m.short",
        ClientSecret = "secret",
        Scope = "api" // optional
    });
});

services.AddHttpClient<MyClient>(client =>
{
    client.BaseAddress = new Uri("https://demo.identityserver.io/api/");
})
.AddClientAccessTokenHandler();

请求发送者MyClient将始终拥有有效的不记名令牌。刷新自动执行。

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

如何使用 IHttpClientFactory 刷新令牌 的相关文章

  • Windows 10 Mobile (10.0.14393) 地理围栏后台任务 (LocationTrigger)

    自从10 0 14393 周年纪念更新 LocationTrigger似乎不起作用 我有 Windows Phone 8 1 应用程序 也适用于 UWP 应用程序 输出到的便携式库Windows Runtime Component图书馆 w
  • 具有不同大小结构的结构数组的 malloc()

    如果每个结构都包含一个大小不同的字符串数组 那么如何正确地 malloc 一个结构数组 因此每个结构可能有不同的大小 并且不可能 realloc 结构体数量 sizeof 结构体名称 after malloc 初始大小 sizeof 结构名
  • 通过增加索引之和来生成排序组合的有效方法

    对于启发式算法 我需要一个接一个地评估特定集合的组合 直到达到停止标准 由于它们很多 目前我正在使用以下内存高效迭代器块生成它们 受到 python 的启发 itertools combinations http docs python o
  • System.IO.IOException:由于意外>数据包格式,握手失败?

    有谁知道这意味着什么 System Net WebException 底层连接已关闭 发送时发生意外错误 gt System IO IOException 由于意外 握手失败 数据包格式 在 System Net Security SslS
  • 在 C# 中生成 HMAC-SHA1

    我正在尝试使用 C 来使用 REST API API 创建者提供了以下用于 hmac 创建的伪代码 var key1 sha1 body var key2 key1 SECRET KEY var key3 sha1 key2 var sig
  • SSL/TLS/HTTPS 站点在 C#/.NET WebBrowser 控件中非常慢,但在 Internet Explorer 中则很好

    背景 我正在修改自动维基浏览器 http en wikipedia org wiki Wikipedia AutoWikiBrowser使用托管在安全服务器上的 MediaWiki 站点 我允许用户通过 C 应用程序中的 WebBrowse
  • 在 C++ 中将成对向量转换为两个独立向量的最快方法

    假设我有一个vector of pair
  • 将字符串中的“奇怪”字符转换为罗马字符

    我需要能够将用户输入仅转换为 a z 罗马字符 不区分大小写 所以 我感兴趣的角色只有26个 然而 用户可以输入他们想要的任何 形式 的字符 西班牙语 n 法语 e 和德语 u 都可以包含用户输入中的重音符号 这些重音符号会被程序删除 我已
  • C++中delete和delete[]的区别[重复]

    这个问题在这里已经有答案了 可能的重复 C 中的删除与删除 运算符 https stackoverflow com questions 2425728 delete vs delete operators in c 我写了一个包含两个指针的
  • 在 C# Winforms 应用程序中嵌入 Windows XP 主题

    我有一个旧版 C Windows 窗体应用程序 其布局是根据 Windows XP 默认主题设计的 由于需要将其作为 Citrix 应用程序进行分发 该应用程序现在看起来像经典主题应用程序 因为 Citrix 不鼓励使用主题系统服务 所以
  • 如何使用MySqlCommand和prepare语句进行多行插入?(#C)

    Mysql 给出了如何使用准备语句和 NET 插入行的示例 http dev mysql com doc refman 5 5 en connector net programming prepared html http dev mysq
  • 获取尚未实例化的类的函数句柄

    我对 C 相当陌生 我想做的事情可能看起来很复杂 首先 我想获取一些函数的句柄以便稍后执行它们 我知道我可以通过以下方式实现这一目标 List
  • 两种类型的回发事件

    1 我发现了两篇文章 每篇文章对两种类型的回发事件的分类都略有不同 一位资源说两种类型的回发事件是Changed事件 其中控件实现 IPostbackDataHandler 当数据在回发之间更改时触发 然后Raised事件 其中控件实现 I
  • 预处理后解析 C++ 源文件

    我正在尝试分析c 使用我定制的解析器的文件 写在c 在开始解析之前 我想摆脱所有 define 我希望源文件在预处理后可以编译 所以最好的方法是运行C Preprocessor在文件上 cpp myfile cpp temp cpp or
  • C++11 动态线程池

    最近 我一直在尝试寻找一个用于线程并发任务的库 理想情况下 是一个在线程上调用函数的简单接口 任何时候都有 n 个线程 有些线程比其他线程完成得更快 并且到达的时间不同 首先我尝试了 Rx 它在 C 中非常棒 我还研究了 Blocks 和
  • 使用 iTextSharp 5.3.3 和 USB 令牌签署 PDF

    我是 iTextSharp 和 StackOverFlow 的新手 我正在尝试使用外部 USB 令牌在 C 中签署 PDF 我尝试使用从互联网上挖掘的以下代码 Org BouncyCastle X509 X509CertificatePar
  • Visual Studio 2017 完全支持 C99 吗?

    Visual Studio 的最新版本改进了对 C99 的支持 最新版本VS2017现在支持所有C99吗 如果没有 C99 还缺少哪些功能 No https learn microsoft com en us cpp visual cpp
  • ASP.NET Core 会话超时

    我记得我们在 ASP NET 中使用了 session timeout 来更改会话超时 如果不更改 则为 20 分钟 我尝试在 Startup cs 中更改 ASP NET Core 3 1 中的会话超时 但没有任何反应 我对操作员使用身份
  • 以 UTF8 而不是 UTF16 输出 DataTable XML

    我有一个 DataTable 我正在使用 WriteXML 创建一个 XML 文件 尽管我在以 UTF 16 编码导出它时遇到问题 并且似乎没有明显的方法来更改它 我了解 NET 在字符串内部使用 UTF 16 这是正确的吗 然后 我通过
  • C#中为线程指定特殊的cpu

    我有 2 个线程 我想告诉其中一个在第一个 cpu 上运行 第二个在第二个 cpu 上运行 例如在具有两个 cpu 的机器中 我怎样才能做到这一点 这是我的代码 UCI UCIMain new UCI Thread UCIThread ne

随机推荐

  • 如何在 XMLHttpRequest 中捕获 Chrome 错误 net::ERR_FILE_NOT_FOUND?

    我想创建 chrome 扩展 它将能够读取本地文件并使用其中编写的代码 我的简单代码是 const readFile filePath gt return new Promise function resolve reject const
  • 服务如何生成和使用公共和秘密 API 密钥?

    Google Stripe 和许多其他公司都有公共 API 密钥和秘密 API 密钥 生成随机字符串很容易 但我的问题是 如何生成公钥和私钥 存储它们并正确使用它们 公共 API 密钥用于告知用户是谁 秘密用于确认用户的身份 我的流程如下
  • Typescript - React 组件中的“找不到名称”错误

    我正在将现有的 React 代码迁移到 TypeScript 并且遇到了很多问题 其中之一是当我创建我的代码时出现很多 找不到名称 错误 js files ts files 这是有问题的代码 import React from react
  • Windows 7 Websocket PlatformNotSupportedException

    我正在使用 Microsoft Azure Devices Client NuGet 包开发一个应用程序 在 Windows 10 上一切都运行良好 但在 Win7 机器上测试时我遇到了这个聚合异常 System PlatformNotSu
  • 如何在 Homebrew 中符号链接 python?

    由于某种原因 当我运行 brew link python 时 没有符号链接 我收到以下错误 我按照它告诉我的去做 但它不起作用 我已经尝试按照它告诉我的去做 但也许我没有把公式名称放在正确的位置 另外 当我执行 which python 时
  • 如何在 SQL Server 中循环插入多条数据?使用 Node JS 乏味

    我有一个 Node JS 项目 它从数组中获取数据data2 使用此数据创建一个对象myObject使用来自 API 的数据获取let url https 然后将其保存到 SQL Server 中的数据库中 我遇到的问题是我遵循MS Doc
  • 在响应中返回 HttpStatusCode

    有没有一种简单的方法可以为我的 api 返回 HttpStatusCode 我找到了一种稍微更详细的方法来做到这一点 return Response AsJson new object HttpStatusCode NoContent 我已
  • 在ant脚本中连接xml文件

    我是 Ant 脚本的新手 我正在寻找如何将文件夹中的所有 xml 文件连接到 ant 脚本中的单个 xml 文件中 在我的项目中 将在文件夹中动态生成 n 个 xml 文件 例如 server1 xml manager xml server
  • 在 iOS 9 和 10 中支持 NSManagedObject fetchRequest() 类方法

    iOS 10 引入了新的类级别fetchRequest 中的方法NSManagedObject 和许多其他开发人员一样 我在上面创建了自己的扩展NSManagedObject其中有一个fetchRequest 方法 当我尝试构建支持 iOS
  • 对数字进行排序 Objective C

    我有一个字符串数组 我使用该方法对其进行排序 TableViewPopoverList sortUsingSelector selector localizedCaseInsensitiveCompare 这些字符串的第一部分是一个数字 但
  • 执行transact-sql语句或批处理时发生异常

    我不断收到错误消息 执行transact sql语句或批处理时发生异常 当尝试在 SQL Server Management Studio 2016 中执行任何操作时 当我尝试创建或编辑登录名 尝试创建新数据库时 基本上当我执行任何操作时
  • 内容从高度为 100% 的 div 溢出

    当我在 Chrome Firefox 或 IE11 中查看此页面时 我注意到将窗口水平调整到最小宽度会导致文本溢出页面底部的白色背景 div div设置了100 的高度 那不是应该继续匹配页面的高度吗 看起来 100 只匹配窗口的高度 但是
  • 为什么 php 接口中的关键词是abstract和void?

    查看 php 手册站点上的 SplSubject 接口并注意到 SplSubject Methods abstract public void attach SplObserver observer abstract public void
  • JRXML 中的多个页面使用 iReport 进行多页报告

    我只是想知道iReport JRXML是否支持多页报表 如果有的话 可以给一些参考样品吗 我并不是要求一份随着数据增长而增长的报告 我有一份静态报告 其中包含多个页面需要处理 每个页面都有不同的页眉 页脚和内容 只是他们需要成为一个单一的一
  • 如何在 Asp.Net Core 6 中从 Secrets.json 获取 ConnectionString?

    我是 Asp Net Core 和 EF 的新手 我正在从数据库端开发一个简单的 CRUD 使用Secrets json文件来隐藏我的连接字符串凭据 但我不知道如何使用 AddDbContext 引用该文件 到目前为止我的代码 public
  • 如何在 Jetpack Compose 中减慢 AnimateScrollToItem 的速度?

    我有一个惰性列表 单击按钮时我将动画滚动到项目 onClick scope launch lazyListState animateScrollToItem selectedIndex 为什么 animateScrollToItem 这么快
  • 使用 pdfkit for python 生成目录

    问题摘要 我无法让目录生成器在 Python 的 pdfkit 中工作 我尝试过的 传递参数toc 我当前的代码 toc xsl style sheet toc xsl pdfkit from file book html filename
  • 从矩阵中提取一系列连续向量

    我有一个大矩阵 为了简化起见 gt mat matrix c 1 50 ncol 5 gt mat 1 2 3 4 5 1 1 11 21 31 41 2 2 12 22 32 42 3 3 13 23 33 43 4 4 14 24 34
  • 为什么 v-model 不能与数组和 v-for 循环一起使用?

    我有一个自定义选择组件 它适用于一个简单的变量 但与 v for 一起使用时它将不起作用 https jsfiddle net 7gjkbhy3 19 https jsfiddle net 7gjkbhy3 19
  • 如何使用 IHttpClientFactory 刷新令牌

    我使用 IHttpClientFactory 使用 Net Core 2 2 发送请求并从两个外部 API 接收 HTTP 响应 我正在寻找一个好的策略来使用已存储在 appsettings json 中的刷新令牌来获取新的访问令牌 当当前