如何从 C# WebApi 禁用对 MarkLogic 服务器的预检请求
Posted
技术标签:
【中文标题】如何从 C# WebApi 禁用对 MarkLogic 服务器的预检请求【英文标题】:How to disable preflight request to MarkLogic server from C# WebApi 【发布时间】:2020-09-11 18:44:48 【问题描述】:技术栈如下
.Net core WebApi (C#) MarkLogic 9.0.8.2我们开发了带有基本身份验证的 MarkLogic API,当从 C# WebApi 调用它时,我们在标头中传递凭据。
我们注意到 MarkLogic 访问日志有 2 个条目,即
xx.xxx.xxx.xx - - [18/May/2020:06:05:35 +0000] "GET /getcontent?query=test&offset=1&size=10&format=Extended&sortOrder=ASC&transform=&IncludeFacet=true HTTP/1.1" 401 209 - - xx.xxx.xxx.xx - MLUser [18/May/2020:06:05:35 +0000] "GET /getcontent?query=test&offset=1&size=10&format=Extended&sortOrder=ASC&transform =&IncludeFacet=true HTTP/1.1" 200 44229 - -同样的请求带有 401 即未经授权,然后立即带有 200 即成功。
我们意识到从 C# WebAPI 调用 API 端点是在调用实际请求之前使用 OPTIONS 执行预检请求。
我们发现有发送内容类型为“文本/纯文本”的选项来解决这个问题,但我们不能,因为我们有 JSON 对象,然后我们需要做更多的事情来将文本解析为 JSON 对象。
当我们从 PostMan 调用时,我们面临同样的问题。
因此,当我们在 API 上收到大量请求时,ML API 在防火墙上返回 401 错误,然后 FW 会阻止所有请求,将其视为暴力攻击。
有什么方法可以禁用预检请求调用?
MarkLogicHttpClient _client;
var queryParams = new Dictionary<string, string>
"query", searchRequest.Query ,
"offset", searchRequest.Offset.ToString() ,
"size", searchRequest.Size.ToString() ,
"format", searchRequest.Format ,
"sortOrder", searchRequest.SortOrder.ToString().ToUpper() ,
"transform", transform
;
var searchUri = QueryHelpers.AddQueryString("getcontent", queryParams);
var response = await _client.GetAsync(searchUri);
//Startup.cs
services.AddHttpClient<IMarkLogicClient, MarkLogicHttpClient>(client =>
client.BaseAddress = MarkLogicEndpoint;
)
.ConfigurePrimaryHttpMessageHandler(() =>
new HttpClientHandler
Credentials = new NetworkCredential
UserName = UserName,
Password = Password
);
【问题讨论】:
如何将凭据添加到标头?可以提供代码吗? 您好布伦特,感谢您的回复。我在问题本身中添加了代码。 【参考方案1】:HttpClient 仅在第一次收到来自服务器的带有 WWW-Authenticate 标头的 401 响应后才发送 Authorization 标头。
默认情况下,HttpClient 在授权每个请求之前等待 401 响应。
有两种方法可以减少 401 响应的数量。
设置HttpClientHandler.PreAuthenticate
属性
services.AddHttpClient<IMarkLogicClient, MarkLogicHttpClient>(client =>
client.BaseAddress = MarkLogicEndpoint;
)
.ConfigurePrimaryHttpMessageHandler(() =>
new HttpClientHandler
// cache the WWW-Authenticate response and send Authorize header
// on all subsequent requests
PreAuthenticate = true,
Credentials = new NetworkCredential
UserName = UserName,
Password = Password
);
或者,手动将 Authorize Header 添加到 HttpClient.DefaultRequestHeaders
services.AddHttpClient<IMarkLogicClient, MarkLogicHttpClient>(client =>
// construct HTTP Basic Authorization header and send on every request
// Do not add credentials to HttpClientHandler
var authorization= "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Username + ":" + Password));
client.BaseAddress = MarkLogicEndpoint;
client.DefaultRequestHeaders.Add("Authorization", authorization);
);
【讨论】:
您好布伦特,感谢您的示例回复。因此,当我使用 PreAutheticate 实现时,它仍然是第一次抛出 401 错误,然后是所有 200 个请求,但是如果在特定时间服务器中没有请求(我看到 2 分钟内是否没有请求),我再次看到 401 错误。使用第二种方法,我们永远不会收到 401 错误?我问是因为要测试,我需要遵循漫长的过程。我的意思是实际上我想禁用预检请求。 使用第二种方法,您应该期望没有预检和 401 你好布伦特,谢谢,所以你的意思是,是 httphandler 导致了预检请求? 是的,HttpClient 和 HttpHandler 实现 HTTP 基本身份验证的方式会导致零星的身份验证预检请求,即使启用了 PreAuthenticate。硬编码 Authorize 标头,如第二个示例所示,从不进行身份验证预检。 感谢布伦特的回复。现在 401 的频率非常低,但我仍然在访问日志文件中看到 401 错误,然后是 200 的相同请求。我重新启动服务也是为了确保它不会从缓存中获取任何内容。而且他们不是在第一个请求的开始,而是介于两者之间。硬编码也在做某种缓存?尽管 401 的数量很少,但似乎第二种方法仍在发生预检请求。以上是关于如何从 C# WebApi 禁用对 MarkLogic 服务器的预检请求的主要内容,如果未能解决你的问题,请参考以下文章
从 C# 调用 WebApi 获取异常 HttpRequestException
从统一 C# POST json 字符串到 webAPI; HttpClient 还是 UnityWebRequest?