2017-02-02 2 views
12

Я разрабатываю веб-приложение ASP.Net Core, где мне нужно создать своего рода «прокси-сервер аутентификации» для другого (внешнего) веб-сервиса.Создание прокси для другого веб-api с ядром Asp.net

Что я имею в виду под аутентификационным прокси-сервером, так это то, что я получу запросы через определенный путь своего веб-приложения и должен будет проверить заголовки этих запросов для токена аутентификации, которые я выпустил ранее, а затем перенаправить все запросы с той же строкой/контентом запроса к внешнему веб-API, которое мое приложение будет аутентифицировать с помощью HTTP Basic auth.

Вот весь процесс в псевдокоде

  • Клиент запрашивает маркер, сделав POST в уникальный URL, который я послал его раньше
  • Мое приложение посылает ему уникальный маркер в ответ на это сообщение
  • Клиент делает запрос GET к определенному URL моего приложения, скажем /extapi и добавляет аутентификации-маркер в заголовке HTTP
  • Мое приложение получает запрос, проверяет, что Auth-маркер присутствует и действует
  • Мое приложение делает то же запрос на внешний веб-API и опознает запрос с использованием BASIC аутентификации
  • Мое приложение получает результат из запроса и отправляет его обратно клиенту

Вот что у меня есть сейчас , Кажется, что он работает нормально, но мне интересно, действительно ли это так должно быть сделано или если нет более элегантного или лучшего решения? Может ли это решение создать проблемы в конечном итоге для масштабирования приложения?

[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 из http://someexternalapp.com/api/

Кроме того, есть более простой подход для маркеров создания/маркеров проверки, чем делать это вручную?

+0

IIS обратный прокси –

+0

Но что делать, если вы не размещаете на IIS? Я мог бы пойти на хостинг с помощью Kestrel на образ Docker или что-то в этом роде. – Gimly

+0

Вы можете использовать любой сервер в качестве обратного прокси. Поэтому разверните экспресс-приложение с обратным прокси или любым другим популярным веб-сервером с обратным прокси ... –

ответ

10

Я закончил реализацию прокси-промежуточного программного обеспечения, вдохновленного a project in Asp.Net's GitHub.

В основном он использует промежуточное программное обеспечение, которое считывает полученный запрос, создает из него копию и отправляет его обратно настроенной службе, считывает ответ от службы и отправляет ее обратно вызывающему абоненту.

+0

Вы могли бы поделиться своими инструментами своего промежуточного программного обеспечения? Если это возможно. Это сильно основано на .Net Core? Благодарю. – Dmitriy

+0

@ Dmitriy Нет, извините, я не могу поделиться реализацией, поскольку она является частью программы с закрытым исходным кодом. Но это в основном тот же код, что и в вопросе, реализованном как промежуточное ПО. Проверьте файл https://github.com/aspnet/Proxy/blob/dev/src/Microsoft.AspNetCore.Proxy/ProxyMiddleware.cs, чтобы получить представление о том, как запустить промежуточное программное обеспечение. – Gimly

+0

спасибо! Я изучу этот пример. Теперь я нахожусь так же, как в вашем примере выше, - создайте простой прокси-контроллер с методами CRUD и по умолчанию запросите на нем любые запросы. В этом контроллере я просто разбираю имя хоста и контроллера в url, меняю хост и порт через словарь из appsettings.json. Но я только начинаю ... – Dmitriy

1

Вот базовая реализация Proxy library for 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(); 
     } 
    } 
} 
+1

Можете ли вы обновить пакет nuget, этот код не работает с опубликованным 0.2.0 – Kugel

+0

Не уверен, что я что-то упустил с помощью этого кода или нет, но я не могу разрешить 'services.AddProxy (...)'. Я использую Microsoft.AspNetCore.Proxy v0.2.0. Кроме того, метод 'RunProxy' не принимает параметр' Uri' в качестве параметра. Какая версия была использована для этого примера? – Allan

+0

Я использовал v0.2 nuget из каналов предварительного просмотра: https://dotnet.myget.org/feed/aspnetcore-release/package/nuget/Microsoft.AspNetCore.Proxy –