Gim*_*mly 35 c# asp.net asp.net-core-mvc asp.net-core-webapi
我正在开发一个ASP.Net Core Web应用程序,我需要为另一个(外部)Web服务创建一种"身份验证代理".
我的身份验证代理的意思是我将通过我的Web应用程序的特定路径接收请求,并且必须检查这些请求的标头以获取我之前发布的身份验证令牌,然后将所有请求重定向到相同的请求字符串/内容到我的应用程序将通过HTTP Basic身份验证进行身份验证的外部Web API.
这是伪代码的整个过程
/extapi并在HTTP标头中添加auth-token这就是我现在所拥有的.它似乎工作正常,但我想知道它是否真的应该这样做,或者是否有更优雅或更好的解决方案?从长远来看,该解决方案是否会为扩展应用程序带来问题?
[HttpGet]
public async Task GetStatement()
{
//TODO check for token presence and reject if issue
var queryString = Request.QueryString;
var response = await _httpClient.GetAsync(queryString.Value);
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
[HttpPost]
public async Task PostStatement()
{
using (var streamContent = new StreamContent(Request.Body))
{
//TODO check for token presence and reject if issue
var response = await _httpClient.PostAsync(string.Empty, streamContent);
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType?.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
}
Run Code Online (Sandbox Code Playgroud)
_httpClient作为一个HttpClient类实例化别的地方,是一个独立的,并用BaseAddress的http://someexternalapp.com/api/
此外,令牌创建/令牌检查比手动更简单吗?
Gim*_*mly 14
我最终实现了一个受Asp.Net的GitHub项目启发的代理中间件.
它基本上实现了一个中间件,它读取收到的请求,从中创建一个副本并将其发送回配置的服务,从服务中读取响应并将其发送回调用者.
这篇文章讨论了在 C# 或 ASP.NET Core 中编写一个简单的 HTTP 代理逻辑。并允许您的项目将请求代理到任何其他 URL。这不是为您的 ASP.NET Core 项目部署代理服务器。
在项目的任何位置添加以下代码。
public static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, Uri uri)
{
var request = context.Request;
var requestMessage = new HttpRequestMessage();
var requestMethod = request.Method;
if (!HttpMethods.IsGet(requestMethod) &&
!HttpMethods.IsHead(requestMethod) &&
!HttpMethods.IsDelete(requestMethod) &&
!HttpMethods.IsTrace(requestMethod))
{
var streamContent = new StreamContent(request.Body);
requestMessage.Content = streamContent;
}
// Copy the request headers
foreach (var header in request.Headers)
{
if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
}
requestMessage.Headers.Host = uri.Authority;
requestMessage.RequestUri = uri;
requestMessage.Method = new HttpMethod(request.Method);
return requestMessage;
}
Run Code Online (Sandbox Code Playgroud)
此方法隐蔽用户发送HttpContext.Request到一个可重用的HttpRequestMessage. 因此,您可以将此消息发送到目标服务器。
在您的目标服务器响应之后,您需要将响应复制HttpResponseMessage到HttpContext.Response以便用户的浏览器获取它。
public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)
{
if (responseMessage == null)
{
throw new ArgumentNullException(nameof(responseMessage));
}
var response = context.Response;
response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
foreach (var header in responseMessage.Content.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
response.Headers.Remove("transfer-encoding");
using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(response.Body, _streamCopyBufferSize, context.RequestAborted);
}
}
Run Code Online (Sandbox Code Playgroud)
现在准备工作已经完成。回到我们的控制器:
private readonly HttpClient _client;
public YourController()
{
_client = new HttpClient(new HttpClientHandler()
{
AllowAutoRedirect = false
});
}
public async Task<IActionResult> Rewrite()
{
var request = HttpContext.CreateProxyHttpRequest(new Uri("https://www.google.com"));
var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, HttpContext.RequestAborted);
await HttpContext.CopyProxyHttpResponse(response);
return Ok();
}
Run Code Online (Sandbox Code Playgroud)
并尝试访问它。它将被代理到 google.com
如果有人感兴趣,我会使用Microsoft.AspNetCore.Proxy代码,并使它与中间件更好。
在这里查看:https : //github.com/twitchax/AspNetCore.Proxy。NuGet此处:https://www.nuget.org/packages/AspNetCore.Proxy/。Microsoft存档了这篇文章中提到的另一篇文章,我计划对这个项目中的任何问题做出回应。
基本上,它允许您在通过args路由并计算代理地址的方法上使用属性,从而使反向代理另一个Web服务器更加容易。
[ProxyRoute("api/searchgoogle/{query}")]
public static Task<string> SearchGoogleProxy(string query)
{
// Get the proxied address.
return Task.FromResult($"https://www.google.com/search?q={query}");
}
Run Code Online (Sandbox Code Playgroud)
我很幸运地使用了twitchax 的 AspNetCore.Proxy NuGet 包,但无法使用twitchax 的答案ProxyRoute中显示的方法让它工作。(对我来说很可能是一个错误。)
相反,我在 Statup.cs Configure() 方法中定义了映射,类似于下面的代码。
app.UseProxy("api/someexternalapp-proxy/{arg1}", async (args) =>
{
string url = "https://someexternalapp.com/" + args["arg1"];
return await Task.FromResult<string>(url);
});
Run Code Online (Sandbox Code Playgroud)
Twitchax 的答案似乎是目前最好的解决方案。在研究过程中,我发现 Microsoft 正在开发一种更强大的解决方案,该解决方案适合 OP 试图解决的确切问题。
回购: https: //github.com/microsoft/reverse-proxy
Preview 1 的文章(他们实际上刚刚发布了 prev 2):https ://devblogs.microsoft.com/dotnet/introducing-yarp-preview-1/
从文章...
YARP 是一个创建反向代理服务器的项目。当我们注意到 Microsoft 内部团队提出的一系列问题时,他们要么正在为其服务构建反向代理,要么一直在询问构建反向代理的 API 和技术,因此我们决定让他们一起开发一个通用的解决方案。 ,已成为 YARP。
YARP 是一个反向代理工具包,用于使用 ASP.NET 和 .NET 的基础结构在 .NET 中构建快速代理服务器。YARP 的主要区别在于它被设计为易于定制和调整,以满足每个部署场景的特定需求。YARP 插入 ASP.NET 管道来处理传入请求,然后拥有自己的子管道来执行将请求代理到后端服务器的步骤。客户可以根据需要添加额外的模块或更换库存模块。
...
YARP 可与 .NET Core 3.1 或 .NET 5 预览版 4(或更高版本)配合使用。从https://dotnet.microsoft.com/download/dotnet/5.0下载 .NET 5 SDK 预览版 4(或更高版本)
更具体地说,他们的示例应用程序之一实现了身份验证(就OP的原始意图而言) https://github.com/microsoft/reverse-proxy/blob/master/samples/ReverseProxy.Auth.Sample/Startup.cs
借助 James Lawruk 的回答/sf/answers/3790493451/来使 twitchax 代理属性正常工作,我还收到 404 错误,直到我在 ProxyRoute 属性中指定完整路由。我的静态路由位于单独的控制器中,并且控制器路由的相对路径不起作用。
这有效:
public class ProxyController : Controller
{
[ProxyRoute("api/Proxy/{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
Run Code Online (Sandbox Code Playgroud)
这不会:
[Route("api/[controller]")]
public class ProxyController : Controller
{
[ProxyRoute("{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
Run Code Online (Sandbox Code Playgroud)
希望这对某人有帮助!
一个不错的反向代理中间件实现也可以在这里找到:https : //auth0.com/blog/building-a-reverse-proxy-in-dot-net-core/
请注意,我在这里替换了这一行
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
Run Code Online (Sandbox Code Playgroud)
和
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToString());
Run Code Online (Sandbox Code Playgroud)
在我的情况下,如果没有我的修改,则不会添加原始标头(例如,带有不记名令牌的授权标头)。
| 归档时间: |
|
| 查看次数: |
37414 次 |
| 最近记录: |