ASP.NET Core - 实现Http自定义请求头策略
前言
在正常的情况下,当我们系统用到JWT认证方式时,需要在Http请求头添加Authorization: XXX,这样在后台服务的控制器中打上[Authorize]授权标签,就限定所有的请求必须通过鉴权方可访问。
在【ASP.NET Core - 基于IHttpContextAccessor实现系统级别身份标识】这篇文章中我们能够注意到,通过IHttpContextAccessor获取基于请求生成的HttpContext后,我们是能够拿到基于该次请求的所有http信息的。这就给予了我们可以基于Http的请求做自定义请求头的策略来满足我们业务的扩展。
场景
在不少的场景中,特别是多租户的场景中,我们是需要知道当前是哪个租户下的用户在操作,而我们又不需要把这租户作为业务参数传递,毕竟如果按照业务参数这样的方式去实现的话,就好比从源头传入了一个污染源,需要一路污染下去,这是非常不推荐的方式,这时就可以利用自定义http请求头来传递这个参数,在最终需要用到这个参数的时候获取出来。
在我们的系统层面,例如我们的应用部署在K8S集群中的网络,在网关层解析了JWT通过认证后放行之后,内网的应用服务可以依赖内网的保护把JWT的认证删减掉(这样在一定程上是可以提高性能的),我们就可以通过以下自定义头的实现方式,把租户信息携带在http头部,一路传递下去。
实现
类似于我们在【ASP.NET Core - 基于IHttpContextAccessor实现系统级别身份标识】中的IHttpContextAccessor实现方式一样,我们先定义我们的IHttpHeaderAccessor用来获取HttpHeader
/// <summary>
/// httpcontext的header
/// </summary>
public interface IHttpHeaderAccessor
{
/// <summary>
/// the httpheader
/// </summary>
IHeaderDictionary HttpHeader { get; }
}
HttpHeaderAccessor 的实现
/// <summary>
/// httpheader访问器
/// </summary>
public class HttpHeaderAccessor : IHttpHeaderAccessor
{
/// <summary>
/// the HttpContextAccessor
/// </summary>
private readonly IHttpContextAccessor _httpContextAccessor; public IHeaderDictionary HttpHeader => _httpContextAccessor.HttpContext.Request.Headers; /// <summary>
/// ctor
/// </summary>
/// <param name="httpContextAccessor">the HttpContextAccessor</param>
public HttpHeaderAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
}
定义http请求头的自定义参数
public interface ICustomHeaderAccessor
{
/// <summary>
/// 租户Id
/// </summary>
string TenantId { get; }
}
http请求头的自定义参数的获取,这里是直接从头部获取到租户信息
/// <summary>
/// 获取自定义http头
/// </summary>
public class CustomHeaderAccessor : ICustomHeaderAccessor
{
protected IHttpHeaderAccessor _httpHeaderAccessor { get; } /// <summary>
/// ctor
/// </summary>
/// <param name="httpHeaderAccessor"></param>
public CustomHeaderAccessor(IHttpHeaderAccessor httpHeaderAccessor)
{
_httpHeaderAccessor = httpHeaderAccessor;
} /// <summary>
/// 租户Id
/// </summary>
public string TenantId
{
get
{
return _httpHeaderAccessor.HttpHeader[HeaderConst.TenantId];
}
}
}
扩展
在【ASP.NET Core - 基于IHttpContextAccessor实现系统级别身份标识】我们知道IHttpContextAccessor,IHttpHeaderAccessor,ICustomHeaderAccessor都需要注册,有了上面的这些方法定义,我们定义一个ServiceCollection的扩展方法进行注册
/// <summary>
/// 基于IServiceCollection的扩展类
/// </summary>
public static class ServiceCollectionExtension
{
/// <summary>
/// 注册IHttpContextAccessor,IHttpHeaderAccessor和ICustomHeaderAccessor
/// </summary>
/// <param name="services">the IServiceCollection</param>
/// <returns></returns>
public static IServiceCollection AddCustomHttpHeader(this IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IHttpHeaderAccessor, HttpHeaderAccessor>();
services.AddSingleton<ICustomHeaderAccessor, CustomHeaderAccessor>(); return services;
}
}
有了服务的注册,我们还需要一个当前服务的实例提供者,一个ServiceProvider,如下
public class ServiceProviderInstance
{
public static IServiceProvider Instance { get; set; }
}
我们在获取到当前进程的ServiceProvider后,保存到本地静态变量
/// <summary>
/// 基于IApplicationBuilder的扩展
/// </summary>
public static class ServiceProviderExtension
{
/// <summary>
/// 给ServiceProviderInstance赋值ServiceProvider实例
/// </summary>
/// <param name="applicationBuilder">the IApplicationBuilder</param>
/// <returns></returns>
public static IApplicationBuilder UseServiceProviderBulider(this IApplicationBuilder applicationBuilder)
{
ServiceProviderInstance.Instance = applicationBuilder.ApplicationServices; return applicationBuilder;
}
}
这里为什么能够在进程内保存一个静态的ServiceProvider?
是因为在应用启动过程中,已经把Ioc容器构建好,把该注册的对象实例关系都已经保存在Ioc容器中了,这时ServiceProvider在进程内是不会有变化的了(动态注册暂时没在本篇文章的使用范围)。
在这里已经给我们提示了另一种对象实例获取的方式,就是通过这个本地的ServiceProviderInstance来解析自己的所注册的对象实例,而不仅仅是通过构造函数(或者属性)注入的方式。
使用
看看我们如何完成整个流程的注册以及使用。
首选需要在程序启动的时候注册。这里通过注册以及swagger的声明,用来做为本地的调试请求头添加
public void ConfigureServices(IServiceCollection services)
{
// 注册Swagger
services.AddAppSwagger(document =>
{
document.Description = "API"; document.OperationProcessors.Add(new OperationSecurityScopeProcessor("TenantId")); document.DocumentProcessors.Add(new SecurityDefinitionAppender("TenantId", new NSwag.OpenApiSecurityScheme
{
Type = NSwag.OpenApiSecuritySchemeType.ApiKey,
Name = "TenantId",
In = NSwag.OpenApiSecurityApiKeyLocation.Header,
Description = "租户Id"
})); services.AddHttpHeader();
}
获取系统的ServiceProvider并保存到本地。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseServiceProviderBuilder(); // Swagger中间件
app.UseAppSwagger(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
定义应用服务的抽象类
public abstract class ServiceBase
{
/// <summary>
/// 自定义头信息
/// </summary>
protected ICustomHeaderAccessor CustomHeader{ get; set; } /// <summary>
/// ctor
/// </summary>
protected ServiceBase ()
{
CustomHeader = ServiceProviderInstance.Instance.GetRequiredService<ICustomHeaderAccessor>();
}
}
使用层面上的赋值
public class TestService : ServiceBase,ITestService
{
private readonly IRepository<Product> _productRepository; public TestService(IRepository<Product> productRepository)
{
_productRepository = productRepository;
} public Result AddProduct(ProductDto dto)
{
_productRepository.Insert(new Product
{
Name = dto.Name,
...
TenantId = CustomHeader.TenantId
});
}
}
Swagger的本地调用
为了方便调试,我们在上面的注册代码中写入了通过swagger中的请求头携带的http头部请求信息,在每次的本地调用中,可通过以下方式把我们需要传递的自定义信息填充进去。

ASP.NET Core - 实现Http自定义请求头策略的更多相关文章
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
- asp.net core 3.1 自定义中间件实现jwt token认证
asp.net core 3.1 自定义中间件实现jwt token认证 话不多讲,也不知道咋讲!直接上代码 认证信息承载对象[user] /// <summary> /// 认证用户信息 ...
- ASP.NET Core 防止跨站请求伪造(XSRF/CSRF)攻击 (转载)
什么是反伪造攻击? 跨站点请求伪造(也称为XSRF或CSRF,发音为see-surf)是对Web托管应用程序的攻击,因为恶意网站可能会影响客户端浏览器和浏览器信任网站之间的交互.这种攻击是完全有可能的 ...
- asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密。
原文:asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密. GitHub demo https://github.com/zhanglilong23/Asp.NetCore. ...
- asp.net core 实现支持自定义 Content-Type
asp.net core 实现支持自定义 Content-Type Intro 我们最近有一个原本是内网的服务要上公网,在公网上有一层 Cloudflare 作为网站的公网流量提供者,CloudFla ...
- ASP.NET Core中显示自定义错误页面-增强版
之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...
- 使用 Spring RestTemplate 调用 rest 服务时自定义请求头(custom HTTP headers)
在 Spring 3.0 中可以通过 HttpEntity 对象自定义请求头信息,如: private static final String APPLICATION_PDF = "app ...
- Asp.net Core 入门实战 2.请求流程
Asp.Net Core 是开源,跨平台,模块化,快速而简单的Web框架. Asp.net Core官网的一个源码合集,方便一次性Clone,喜欢的(Star),本系列持续更新,也可以通过我的网站访问 ...
- Ajax设置自定义请求头的两种方法
用自定义请求头token为例 方法一 $.ajax({ type: "post", url:"http://127.0.0.1:4564/bsky-app/templat ...
随机推荐
- bzoj1742[Usaco2005 nov]Grazing on the Run 边跑边吃草*&&bzoj3074[Usaco2013 Mar]The Cow Run*
bzoj1742[Usaco2005 nov]Grazing on the Run 边跑边吃草 bzoj3074[Usaco2013 Mar]The Cow Run 题意: 数轴上有n棵草,牛初始在L ...
- 使用pycharm、跳板机连接内网服务器
使用pycharm.跳板机连接内网服务器 接手实验室服务器后,大部分同学在GPU集群上跑程序都是直接在ssh界面上跑,这里想着通过pycharm通过跳板机来连接服务器. 总体就是实验室服务器仅限内网访 ...
- Host是什么?如何设置host文件?
前言 前几天我在使用一些软件和网站时,出了一些小问题,然后我在网上搜解决问题的方法,搜着搜着就看到频繁出现的Host这个词.以前还没有注意到这个东西,因为总觉得它是系统文件,没必要去乱动:但是经过这次 ...
- There are unfinished transactions remaining. Please run yum-complete-transaction as root.
问题:CentOS 运行软件更新时,提示如下错误. 解决办法: 在终端界面,运行 sudo yum-complete-transaction.
- MySQL数据库---记录相关操作
序 表中记录的相关操作一共四种:插入,更新,删除.查询.其中使用最多,也是最难的就是查询. 记录的插入 1. 插入完整数据(顺序插入) 语法一: INSERT INTO 表名(字段1,字段2,字段3… ...
- SQL order by语句
关于order by: order by 语句用于根据指定的列对结果集进行排序,默认按照升序排列. 1. select 字段名 from 表名 where 条件 order by 字段名1 asc/ ...
- Linux字符集的查看及修改[转]
一·查看字符集字符集在系统中体现形式是一个环境变量,以CentOS6.5为例,其查看当前终端使用字符集的方式可以有以下几种方式: 1.[root@david ~]# echo $LANGzh_CN.G ...
- vue学习(九) 使用内联样式设置style样式
/html <div id="app"> //对象就是无序键值对的集合 <h1 :style="{ color:red, 'font-weight':2 ...
- 雪碧图——CSS Sprites(精灵)
在日常开发打开文件包,打开static文件夹,有一张图片,里面融合了这个应用都会用到的小图标,其实,主要是减少应用渲染出现繁多的请求,加速页面渲染. 解决方案:使用css背景定位 icon {widt ...
- 华东师范大学p163页,用闭区间套定理证明数列的可惜收敛准则,被网友解决了。