別の(外部)Webサービスへの一種の「認証プロキシ」を作成する必要があるASP.Net Core Webアプリケーションを開発しています。
認証プロキシとは、Webアプリの特定のパスを介してリクエストを受信し、以前に発行した認証トークンのリクエストのヘッダーを確認し、すべてのリクエストをアプリケーションがHTTP Basic認証を通じて認証する外部Web APIへの同じリクエスト文字列/コンテンツ。
擬似コードの全プロセスはここにあります
/extapi
と言うアプリの特定のURLにGETリクエストを行い、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);
}
}
_httpClient
はHttpClient
クラスであり、他のどこかでインスタンス化され、シングルトンであり、BaseAddress
of http://someexternalapp.com/api/
である
また、トークンの作成/トークンのチェックには、手動で行うよりも簡単な方法がありますか?
Asp.NetのGitHubのプロジェクト に触発されたプロキシミドルウェアを実装することになりました。
基本的には、受信した要求を読み取り、それからコピーを作成して構成済みサービスに送信し、サービスから応答を読み取り、呼び出し元に送信するミドルウェアを実装します。
誰かが興味を持っているなら、Microsoft.AspNetCore.Proxyコードを取得し、ミドルウェアで少し良くしました。
こちらをご覧ください: https://github.com/twitchax/AspNetCore.Proxy 。 NuGetここ: https://www.nuget.org/packages/AspNetCore.Proxy/ 。マイクロソフトは、この投稿で言及されている他の1つをアーカイブし、このプロジェクトの問題に対応する予定です。
基本的に、引数を使用してルートを取得し、プロキシされたアドレスを計算するメソッドで属性を使用できるようにすることで、別の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}");
}
James Lawrukの答えをピギーバッキング https://stackoverflow.com/a/54149906/6596451 twitchax Proxy属性を機能させるために、フルルートを指定するまで404エラーが発生していましたProxyRoute属性。静的ルートが別のコントローラーにあり、コントローラーのルートからの相対パスが機能していませんでした。
これはうまくいきました:
public class ProxyController : Controller
{
[ProxyRoute("api/Proxy/{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
これはしません:
[Route("api/[controller]")]
public class ProxyController : Controller
{
[ProxyRoute("{name}")]
public static Task<string> Get(string name)
{
return Task.FromResult($"http://www.google.com/");
}
}
これが誰かを助けることを願っています!
ASP.NET Coreのプロキシライブラリ の基本的な実装を次に示します。
これは承認を実装しませんが、ASP.NET Coreを使用した単純なリバースプロキシを探している人にとっては便利です。これは開発段階でのみ使用します。
using System;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
namespace Sample.Proxy
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(options =>
{
options.AddDebug();
options.AddConsole(console =>
{
console.IncludeScopes = true;
});
});
services.AddProxy(options =>
{
options.MessageHandler = new HttpClientHandler
{
AllowAutoRedirect = false,
UseCookies = true
};
options.PrepareRequest = (originalRequest, message) =>
{
var Host = GetHeaderValue(originalRequest, "X-Forwarded-Host") ?? originalRequest.Host.Host;
var port = GetHeaderValue(originalRequest, "X-Forwarded-Port") ?? originalRequest.Host.Port.Value.ToString(CultureInfo.InvariantCulture);
var prefix = GetHeaderValue(originalRequest, "X-Forwarded-Prefix") ?? originalRequest.PathBase;
message.Headers.Add("X-Forwarded-Host", Host);
if (!string.IsNullOrWhiteSpace(port)) message.Headers.Add("X-Forwarded-Port", port);
if (!string.IsNullOrWhiteSpace(prefix)) message.Headers.Add("X-Forwarded-Prefix", prefix);
return Task.FromResult(0);
};
});
}
private static string GetHeaderValue(HttpRequest request, string headerName)
{
return request.Headers.TryGetValue(headerName, out StringValues list) ? list.FirstOrDefault() : null;
}
public void Configure(IApplicationBuilder app)
{
app.UseWebSockets()
.Map("/api", api => api.RunProxy(new Uri("http://localhost:8833")))
.Map("/image", api => api.RunProxy(new Uri("http://localhost:8844")))
.Map("/admin", api => api.RunProxy(new Uri("http://localhost:8822")))
.RunProxy(new Uri("http://localhost:8811"));
}
public static void Main(string[] args)
{
var Host = new WebHostBuilder()
.UseKestrel()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
Host.Run();
}
}
}
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);
});
ニースのリバースプロキシミドルウェアの実装もここにあります: https://auth0.com/blog/building-a-reverse-proxy-in-dot-net-core/
ここでこの行を置き換えたことに注意してください
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
と
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToString());
私の場合、元のヘッダー(たとえば、ベアラートークンを含む認証ヘッダーなど)は、変更しない限り追加されません。