tutorial net español asp apicontroller c# asp.net asp.net-core-mvc asp.net-core-webapi

c# - español - asp.net core web api 2



Creando un proxy para otra API web con el núcleo de Asp.net (3)

Aquí hay una implementación básica de la biblioteca Proxy para ASP.NET Core :

Esto no implementa la autorización, pero podría ser útil para alguien que busque un proxy inverso simple con ASP.NET Core. Solo usamos esto para las etapas de desarrollo.

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(); } } }

Estoy desarrollando una aplicación web ASP.Net Core donde necesito crear un tipo de "proxy de autenticación" para otro servicio web (externo).

Lo que quiero decir con proxy de autenticación es que recibiré solicitudes a través de una ruta específica de mi aplicación web y tendré que revisar los encabezados de esas solicitudes de un token de autenticación que habré emitido antes, y luego redirigir todas las solicitudes con el misma cadena / contenido de solicitud a una API web externa con la que mi aplicación se autenticará a través de la autenticación HTTP básica.

Aquí está todo el proceso en pseudo-código

  • El cliente solicita un token haciendo un POST a una URL única que le envié anteriormente
  • Mi aplicación le envía un token único en respuesta a este POST
  • El cliente realiza una solicitud GET a una URL específica de mi aplicación, por ejemplo /extapi y agrega el token de autenticación en el encabezado HTTP
  • Mi aplicación recibe la solicitud, comprueba que el token de autenticación está presente y es válido
  • Mi aplicación realiza la misma solicitud a la API web externa y autentica la solicitud mediante la autenticación BASIC
  • Mi aplicación recibe el resultado de la solicitud y lo envía de vuelta al cliente

Esto es lo que tengo por ahora. Parece que funciona bien, pero me pregunto si es realmente la forma en que esto debería hacerse o si no hay una solución más elegante o mejor para esto. ¿Podría esa solución crear problemas a largo plazo para escalar la aplicación?

[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 es una clase HttpClient instanciada en otro lugar y es un singleton y con una BaseAddress de BaseAddress de http://someexternalapp.com/api/

Además, ¿hay un enfoque más simple para la creación de token / token check que hacerlo manualmente?


Si alguien está interesado, tomé el código Microsoft.AspNetCore.Proxy y lo mejoré un poco con middleware.

Compruébelo aquí: https://github.com/twitchax/AspNetCore.Proxy . NuGet aquí: https://www.nuget.org/packages/AspNetCore.Proxy/ . Microsoft archivó el otro que se menciona en esta publicación, y planeo responder a cualquier problema en este proyecto.

Básicamente, hace que el proxy inverso de otro servidor web sea mucho más fácil al permitirle utilizar atributos en métodos que toman una ruta con argumentos y calculan la dirección de proxy.

[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}"); }


Terminé implementando un middleware proxy inspirado en un proyecto en GitHub de Asp.Net .

Básicamente implementa un middleware que lee la solicitud recibida, crea una copia del mismo y la envía de vuelta a un servicio configurado, lee la respuesta del servicio y la envía al llamante.