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 ...
随机推荐
- 大话深度学习:B站Up主麦叔教你零代码实现图像分类神经网络
之前,我在B站发布了“大话神经网络,10行代码不调包,听不懂你打我!”的视频后,因为简单易懂受到了很多小伙伴的喜欢! 但也有小伙伴直呼不够过瘾,因为大话神经网络只有4个神经元. 也有小伙伴问不写代码, ...
- Python爬虫学习02--pyinstaller
Python爬虫学习02--打包exe可执行程序 1.上一次做了一个爬虫爬取电子书的Python程序,然后发现可以通过pyinstaller进行打包成exe可执行程序.发现非常简单好用 2.这是上次写 ...
- 使用redis完成秒杀系统原理
假设秒杀商品数为100,list名称为winner_user 参考视频教程:https://www.imooc.com/video/15167
- Burp Suite Scanner Module - 扫描模块
Burp Suite Professional 和Enterprise Version的Scaner功能较丰富. 以Professional版本为例,包含Issue activity, Scan qu ...
- Python Ethical Hacking - Intercepting and Modifying Packets
INTERCEPTING & MODIFYING PACKETS Scapy can be used to: Create packets. Analyze packets. Send/rec ...
- mdk/iar汇编区别
在代码移植中,经常遇到iar的代码转换问题,在此不间断记录一些,个人感觉还是IAR的更接近C一些,备查: 1. #ifdef的使用 // IAR #ifdef MACRO_XX #endif // M ...
- 一个深拷贝方法的漏洞与一个javascript经典bug
今天做某个项目,需要函数深拷贝. 在网上随便找了个代码粘上去,结果报错了. /** * * @desc 递归法 对象深拷贝 * @param {Object} * @return {new Objec ...
- 谷歌浏览器又隐藏的HTTPS和WWW前缀
谷歌工程师 Emily Schechter 曾在 Chromium 反馈页面中提到:Chrome 团队一直将简易性.可用性.安全性作为衡量 UI 的标准.为了让 URL 能更好地被用户理解.移除那些容 ...
- 【揭秘】C语言类型转换时发生了什么?
ID:技术让梦想更伟大 作者:李肖遥 链接:https://mp.weixin.qq.com/s/ZFf3imVaJgeesuhl1Kn9sQ 在C语言中,数据类型指的是用于声明不同类型的变量或函数的 ...
- MySQL(二)表的操作与简单数据操作
六大约束:主键约束.外键约束.非空约束.唯一约束.默认约束.自动增加 1.not null非空 2.defaul默认值,用于保证该字段的默认值 ; 比如年龄:1900-10-10 3.primar k ...