我们在项目中集成了Refit,但是在调用接口时,出现了问题,提示未授权的访问。这个问题是怎么导致的呢?我们该怎么处理呢?在这篇文章中我们一起来解决吧。

一、为什么会出现这个问题

让我们来深入分析一下是哪里返回的未授权的访问的提示。首先,我们采用最直接的方法:在IDE中全局搜索整个项目中包含这个提示的代码。经过搜索,我们发现这个提示信息只存在于通用中间件ApplicationMiddleware中。

通过进一步分析代码执行流程,我们定位到问题的根源在于 验证网关签名 环节未能通过验证。为了更深入地了解这个问题,我们需要详细检查验证网关签名的方法ValidateGatewaySignature的执行过程。我们采用断点调试的方式,在该方法的入口处设置断点,然后通过Refit发送测试请求。当请求命中断点时,通过调试器我们清晰地观察到一个关键问题:在请求头中完全不存在X-Gateway-Signature这个关键参数。这就直接导致了验证失败,系统返回未授权访问的提示。

那么,为什么会出现这个问题呢?这涉及到我们系统的架构设计。在正常的访问流程中,所有的请求都应该经过网关进行转发和处理。但是在使用Refit进行服务间通信时,我们采用了一个不同的路径:Refit直接从Nacos注册中心获取了一个健康的服务实例,然后直接向该实例发起请求。这种直接通信的方式绕过了网关,导致请求头中缺少了网关在转发时应该添加的X-Gateway-Signature签名信息。

要解决这个问题,我们有一个相对简单的解决方案:在使用Refit发起请求时,手动添加X-Gateway-Signature到请求头中。这样就能确保请求携带了必要的签名信息,从而通过中间件的验证。这个修改虽然简单,但需要注意保持签名生成的逻辑与网关端保持一致,以确保验证能够顺利通过。

二、解决问题

为了解决这个问题,我们需要对RefitServiceCollectionExtensions这个Refit扩展类进行改造。具体来说,我们要在其中注册一个特殊的DelegatingHandler,它将作为请求管道中的一个重要环节。这个处理器的主要职责是确保每一个通过Refit发出的请求都能携带必要的认证信息。它会自动为请求添加X-Gateway-Signature签名头,这个签名头是通过特定算法根据时间戳和密钥生成的。不仅如此,为了保持系统中用户上下文的连续性,这个处理器还会负责传递用户相关的信息,比如用户ID、用户名等关键数据。通过将这个DelegatingHandler整合到Refit的请求管道中,我们可以在不影响现有业务逻辑的情况下,优雅地解决认证问题,使服务间的通信更加安全可靠。

2.1 新建DelegatingHandler

为了实现网关签名验证和用户信息透传的功能,我们需要在SP.Common类库的Refit文件夹下创建一个专门的处理器类。这个处理器将作为请求管道中的重要一环,负责处理所有通过Refit发出的HTTP请求。我们将这个类命名为GatewaySignatureHandler,它继承自DelegatingHandler基类。这个处理器类将在每个请求发出前自动为其添加必要的签名信息和用户上下文数据,确保下游服务能够正确识别和处理这些请求。让我们看看具体的实现代码:

using System.Net.Http.Headers;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;namespace SP.Common.Refit;/// <summary>
/// 为所有下游 Refit 请求添加网关签名与用户透传头
/// </summary>
public class GatewaySignatureHandler : DelegatingHandler
{private readonly IHttpContextAccessor _httpContextAccessor;private readonly IConfiguration _configuration;public GatewaySignatureHandler(IHttpContextAccessor httpContextAccessor, IConfiguration configuration){_httpContextAccessor = httpContextAccessor;_configuration = configuration;}protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken){// 添加网关签名var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();var secret = _configuration["GatewaySecret"] ?? "SP_Gateway_Secret_2024";var signature = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{timestamp}.{secret}"));request.Headers.Remove("X-Gateway-Signature");request.Headers.Add("X-Gateway-Signature", signature);// 透传用户信息(若存在)var httpContext = _httpContextAccessor.HttpContext;var user = httpContext?.User;if (user?.Identity?.IsAuthenticated == true){var userId = user.FindFirstValue("UserId");var userName = user.FindFirstValue("UserName");var email = user.FindFirstValue("Email");if (!string.IsNullOrEmpty(userId))request.Headers.TryAddWithoutValidation("X-User-Id", userId);if (!string.IsNullOrEmpty(userName))request.Headers.TryAddWithoutValidation("X-User-Name", userName);if (!string.IsNullOrEmpty(email))request.Headers.TryAddWithoutValidation("X-User-Email", email);}// 如果上游带了 Authorization,则透传(有些服务可能需要)if (httpContext?.Request?.Headers?.TryGetValue("Authorization", out var authHeader) == true){if (!request.Headers.Contains("Authorization")){request.Headers.Authorization = AuthenticationHeaderValue.Parse(authHeader!);}}return await base.SendAsync(request, cancellationToken);}
}

让我们详细解析这段代码的实现。处理器的核心逻辑在重写的SendAsync方法中实现。首先,它会生成网关签名。签名的生成采用了时间戳和密钥组合的方式,将当前的UTC时间戳与配置中的网关密钥(如果未配置则使用默认值)拼接后进行Base64编码。这个签名会被添加到请求头的X-Gateway-Signature字段中,用于下游服务的验证。接下来,处理器会处理用户信息的透传。它首先检查当前请求的用户是否已认证,如果已认证,则从用户声明中提取用户ID、用户名和邮箱等信息。这些信息会被分别添加到请求头中,使用X-User-IdX-User-NameX-User-Email等自定义头部字段。这样做的目的是确保下游服务能够获知请求的发起者信息。最后,处理器还会检查是否存在授权头(Authorization),如果存在且目标请求还没有设置授权头,则会将其透传到下游请求中。这个功能特别适用于需要保持认证状态的微服务调用场景。

2.2 注册DelegatingHandler

为了使GatewaySignatureHandler生效,我们需要在Refit的服务注册过程中添加它。具体来说,我们需要在RefitServiceCollectionExtensions类的AddRefitClient方法中注册这个处理器。这个处理器会被添加到HTTP请求管道中,作为请求处理的一个重要环节。通过在服务注册时配置这个处理器,我们可以确保所有的服务间通信都会自动携带必要的网关签名和用户信息,从而保证请求能够顺利通过下游服务的验证。让我们看看具体的实现代码:

// more code ...
public static IHttpClientBuilder AddNacosRefitClient<TClient>(this IServiceCollection services,string serviceName,string? groupName,string? clusterName,string scheme = "http",RefitSettings? refitSettings = null)where TClient : class
{services.AddTransient<GatewaySignatureHandler>();return services.AddRefitClient<TClient>(refitSettings ?? new RefitSettings()).ConfigureHttpClient(c => c.BaseAddress = new Uri("http://placeholder")).AddHttpMessageHandler(sp => new NacosDiscoveryHandler(sp.GetRequiredService<IServiceDiscovery>(),serviceName,groupName ?? "DEFAULT_GROUP",clusterName ?? "DEFAULT",scheme,sp.GetRequiredService<ILogger<NacosDiscoveryHandler>>())).AddHttpMessageHandler<GatewaySignatureHandler>();
}
// more code ...

在上面的代码中,我们通过两个关键步骤来注册和使用GatewaySignatureHandler。首先,services.AddTransient<GatewaySignatureHandler>()将处理器注册为瞬态服务,这意味着每次需要时都会创建一个新的实例,这样可以确保处理器在处理并发请求时的线程安全性。其次,.AddHttpMessageHandler<GatewaySignatureHandler>()将处理器添加到HTTP消息处理管道中,使其能够拦截和处理所有出站的HTTP请求。这样,每个通过Refit发出的请求都会经过这个处理器,自动获得必要的网关签名和用户信息,从而确保请求能够顺利通过下游服务的验证。

三、总结

这篇文章详细探讨了在微服务架构中使用Refit进行服务间通信时遇到的未授权访问问题及其解决方案。通过分析,我们发现问题的根源在于Refit直接调用服务实例时绕过了网关,导致缺少必要的网关签名验证信息。为了解决这个问题,我们实现了一个自定义的DelegatingHandler,它能够自动为所有Refit请求添加网关签名和用户信息。这个处理器不仅确保了请求能够通过下游服务的验证,还实现了用户上下文的透传,使得服务间的通信更加安全可靠。这个解决方案优雅地解决了认证问题,同时保持了代码的整洁性和可维护性,为微服务架构中的服务间通信提供了一个实用的范例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/920504.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/920504.shtml
英文地址,请注明出处:http://en.pswp.cn/news/920504.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nacos登录认证

先看一个现象bootstrap.yml配置如下&#xff1a;spring:application:name: myservicecloud:nacos:discovery:server-addr: 127.0.0.1:8848username: nacospassword: nacosconfig:prefix: testfile-extension: ymlusername: nacos123password: nacos注意&#xff1a;配置中nacos…

论文阅读:arixv 2025 WideSearch: Benchmarking Agentic Broad Info-Seeking

WideSearch&#xff1a;大规模信息检索基准测试 https://arxiv.org/pdf/2508.07999 字节&#xff1a;Agent大规模信息获取基准WideSearch WideSearch&#xff1a;揭示 AI 智能体缺失的「广度」能力 Project Page: https://widesearch-seed.github.io/ get the data&#x…

【Docker基础】Docker-compose进阶配置:资源限制与高可用部署

目录 引言 1 Docker资源限制基础概念 1.1 为什么需要资源限制 1.2 Docker资源限制的类型 2 CPU与内存资源限制配置 2.1 传统资源限制方式&#xff08;version 2&#xff09; 2.2 现代资源限制方式&#xff08;version 3 deploy.resources&#xff09; 关键参数解释&…

SQL优化--OR

优化 SQL 中的 OR 条件是一个非常常见的性能调优问题。OR 操作符经常会导致性能下降&#xff0c;因为它使得数据库优化器难以高效地使用索引。下面我将从浅入深地为你讲解优化 OR 的多种策略&#xff0c;并附上示例。为什么 OR 性能往往较差&#xff1f;在简单的 WHERE 子句中&…

Java试题-选择题(21)

Java试题-选择题(21) 题目 有关线程的叙述正确的是 ? A:可以获得对任何对象的互斥锁定 B:通过继承Thread类或实现Runnable接口,可以获得对类中方法的互斥锁定 C:线程通过使用synchronized关键字可获得对象的互斥锁定 D:线程调度算法是平台独立的 下面有关forward和re…

预测模型及超参数:3.集成学习:[1]LightGBM

想象你是一位乐队指挥&#xff0c;你的任务是协调乐队中的每位音乐家&#xff0c;以演奏出一场完美的音乐会。每位音乐家&#xff08;即决策树&#xff09;擅长不同的乐器或乐章。在指挥过程中&#xff0c;你通过调节各位音乐家演奏的强度&#xff08;模型参数&#xff09;&…

Jetson进行旋转目标检测推理实现大疆无人机飞行控制

源码结构 大疆PSDK源码地址&#xff1a; https://github.com/dji-sdk/Payload-SDK其目录结构如下&#xff1a; Payload-SDK-master ├── CMakeLists.txt ├── doc │ ├── dji_sdk_code_style │ └── simple_model ├── EULA.txt ├── LICENSE.txt ├── psd…

阿里云百炼智能体连接云数据库实践(DMS MCP)

这篇文章主要是通过使用阿里云的百炼智能体与阿里云的serverless来实现数据库的操作 欢迎一起交流&#xff01;&#xff01; 首先&#xff0c;当然是选择自己需要的数据库啦 在阿里云控制台选择产品 - > 数据库 - > 数据管理DMS进来的界面如下所示 第一次进来的时候是…

某商店JS混淆补环境与纯算逆向分析

文章目录1. 写在前面2. 接口分析3. 补环境分析4. 纯算法还原【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并…

如何安装 mysql-installer-community-8.0.21.0.tar.gz(Linux 详细教程附安装包下载)​

这是一个 ​Linux 下 MySQL 8.0.21 的压缩安装包&#xff0c;虽然名字里有 installer&#xff0c;但它其实就是一个压缩好的二进制安装包&#xff0c;不是 Windows 那种图形化安装程序。 一、准备工作 确保你已经有&#xff1a; Linux 系统&#xff08;比如 Ubuntu、CentOS、…

IDEA-琴澳研究中心及学术联盟启动,产研协同赋能区域发展

8月30日&#xff0c;IDEA-琴澳中心主导研发的Smaray渲染引擎将发布可免费下载的Tech Preview&#xff08;技术预览版&#xff09;。本次发布标志着粤港澳大湾区在政产研协同创新实现成果落地&#xff0c;也是产业“人工智能”的探索迈进。Smaray是国内首个公开服务的、AI驱动的…

如何备份 TECNO 手机上的短信

许多 TECNO 用户都在寻找方法&#xff0c;以防止因手机损坏、被盗或恢复出厂设置而导致重要对话意外丢失&#xff0c;确保在需要时能够访问他们的数据。还有些人希望在释放设备存储空间的同时&#xff0c;仍然保留旧消息的副本以供日后参考。如果你一直在寻找“备份 TECNO 短信…

OpenAI Sora深度解析:AI视频生成技术如何重塑广告电商行业?影业合作已落地

最近刷到一条超震撼的视频&#xff1a;咖啡杯从桌角滑落&#xff0c;在空中转了半圈居然自己弹回桌面&#xff0c;牛奶一滴没洒。你猜怎么着&#xff1f;这居然是AI生成的&#xff0c;就是OpenAI那个叫Sora的工具做的。是不是觉得有点不可思议&#xff1f;现在这技术已经能做到…

力扣p1011在D天送达包裹的能力 详解

题目如下&#xff1a;代码如下&#xff0c;先看代码&#xff0c;再看思路&#xff1a;注意&#xff0c;从check函数下方的left处看&#xff0c;我认为难点在于以啥来二分&#xff0c;都说求啥拿啥分&#xff0c;但实际无从下手&#xff0c;关键在于如何寻找边界&#xff0c;此处…

React Three Fiber

下面&#xff0c;我们来系统的梳理关于 React Three Fiber&#xff1a;WebGL 与 React 的基本知识点&#xff1a; 一、React Three Fiber 核心概念 1.1 什么是 React Three Fiber&#xff1f; React Three Fiber&#xff08;R3F&#xff09;是一个用于 Three.js 的 React 渲染…

YARN架构解析:深入理解Hadoop资源管理核心

YARN架构解析&#xff1a;深入理解Hadoop资源管理核心 &#x1f31f; 你好&#xff0c;我是 励志成为糕手 &#xff01; &#x1f30c; 在代码的宇宙中&#xff0c;我是那个追逐优雅与性能的星际旅人。 ✨ 每一行代码都是我种下的星光&#xff0c;在逻辑的土壤里生长成璀璨的银…

爬虫代理的核心作用、分类及使用要点

在数据采集场景中&#xff0c;爬虫代理作为“中间传输节点”&#xff0c;通过转发爬虫请求、隐藏真实IP地址&#xff0c;解决传统爬虫面临的诸多限制&#xff0c;其核心价值体现在三个方面&#xff1a;突破IP封锁与访问限制&#xff1a;多数网站会对高频请求的IP进行封锁&#…

EXCEL开发之路(三)sheets梯形样式设计—仙盟创梦IDE

在蔬菜批发行业&#xff0c;高效的信息管理与操作便捷性对于业务的顺畅开展至关重要。梯形 Nav&#xff08;导航栏&#xff09;切换这一设计&#xff0c;看似只是界面交互的小细节&#xff0c;实则在提升用户体验、优化业务流程等方面有着不可忽视的意义&#xff0c;对于初学者…

Unity游戏打包——iOS打包pod的重装和使用

本文由 NRatel 历史笔记整理而来&#xff0c;如有错误欢迎指正。 一、重装 pod 和使用 1、下载安装 rvm curl -L get.rvm.io | bash -s stable 2、使环境变量生效 (zsh) source ~/.zshrc source ~/.profile 3、查看rvm版本 rvm -v 4、重装ruby 关闭mac sip&#xff08;可能需…

AWS OpenSearch 可观测最佳实践

AWS OpenSearch 介绍 OpenSearch 是一种全面开源搜索和分析引擎&#xff0c;使用案例包括日志分析、实时应用程序监控、点击流分析等。Amazon OpenSearch Service 是一项托管服务&#xff0c;让用户能够在 AWS 云中轻松部署、运行并扩展 OpenSearch 集群。 观测云 观测云是一…