Map wildcard in .NET Core WebApplication - c#

How can I create the request mapping so that all requests GET, POST, PUT, ... and all paths execute the same method.
var application = WebApplication.Create();
application.Map("/", () =>
{
return "This is all I do!";
});
application.Run("http://localhost:8080");
My guess is that there is a wildcard pattern that will work, but i have tried the following without success: "/", "*", "/*" and "/**".

You can use application.Run with the RequestDelegate parameter instead of Map, to handle any and all requests:
public static void Main()
{
var application = WebApplication.Create();
application.Run(async context =>
{
await context.Response.WriteAsync("This is all I do!");
});
application.Run("http://localhost:8080");
}

See the Wildcard and catch all routes section of the docs:
app.Map("/{*rest}", (string rest) => rest);
Or you can use "catch all" middleware:
app.Use(async (HttpContext ctx, Func<Task> _) =>
{
await ctx.Response.WriteAsync("Hello World!");
});

Related

Return unauthorized in Ocelot API Gateway Middleware

A this moment, i've an Ocelot API Gateway in my microservice, but i recently i was looking how to invalidate a JWT, and the best way to do this in my project is using a blacklist, so i decided to use a middleware pre authorization to check in my Redis cache the list of invalid JWT. I've looked for solutions to force return a 401 with custom message if the token is in the cache, but i can't find a functional solution. Below is my try:
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, IDistributedCache cache) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapGet("/", async context => {
await context.Response.WriteAsync("Hello World!");
});
});
var configuration = new OcelotPipelineConfiguration {
PreAuthorizationMiddleware = async (ctx, next) => {
string token = ctx.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
if (!string.IsNullOrEmpty(token)) {
string blacklist = await cache.GetStringAsync(token);
if (!string.IsNullOrEmpty(blacklist)) {
ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await ctx.Response.WriteAsync("Custom Message");
return;
}
}
await next.Invoke();
}
};
await app.UseOcelot(configuration);
}
Can someone help me? The solutions i've tried only returns HTTP status code 500 or always 401.
Once you are in Ocelot's pipeline, you have to play Ocelot's game. It uses special objects and extension methods on HttpContext.Items dictionary to pass data between middlewares. Specifically for errors it has 2 extension methods SetError and UpsertErrors. So you need to add this after checking the black list:
if (!string.IsNullOrEmpty(blacklist))
{
ctx.Items.SetError(new UnauthorizedError("your custom message"));
return;
}

How can I reject all request except GET request

I am building .NET 5 WebAPI.
I need a filter or policy that rejects all verbs except GET even if the route and the verb do match.
Can I do this in Startup class?
Using MapWhen you can branch based on a predicate:
app.MapWhen(context => !context.Request.Method.Equals("GET", StringComparison.InvariantCultureIgnoreCase),
(IApplicationBuilder builder) =>
{
builder.Run(async context =>
{
await Task.FromResult(context.Response.StatusCode = StatusCodes.Status406NotAcceptable);
});
});

How can I stop a request in Ocelot's PreAuthenticationMiddleware?

I have to do some checks on the request's jwt before ocelot authentication, so I'm doing them within the PreAuthenticationMiddleware like this:
var config = new OcelotPipelineConfiguration
{
PreAuthenticationMiddleware = async (ctx, next) =>
{
var jwt = ctx.HttpContext.Request.Headers["Authorization"];
if (jwtIsOk(jwt)) next.Invoke();
// else ...
}
};
app.UseOcelot(config).Wait();
Instead of not-invoking next, is it possible to return a custom response?
I'd like to return a 401 error
I think this is what you are looking for :
var configuration = new OcelotPipelineConfiguration
{
PreAuthenticationMiddleware = async (ctx, next) =>
{
if (xxxxxx)
{
ctx.Errors.Add(new UnauthenticatedError("Your message"));
return;
}
await next.Invoke();
}
};
In this case I'm using UnauthenticatedError(an Ocelot's class), it will ends with 401. There are more like this. You can also create your own one inheriting from Ocelot.Errors.Error.

ChallengeAsync() from HttpContext does not redirect

We have a javascript app "wrapped" in an ASP Core MVC Application. Each AJAX-request from the javascript app hits a controller decorated with [Authorize].
In our startup method we've defined an AuhenticationScheme pointing toward our Identity Server. And then another scheme for the cookies that they are ultimately signed in as.
To ensure that all requests coming in are authenticated we use the following:
app.Use(async (context, next) =>
{
if (!context.User.Identity.IsAuthenticated)
{
string auth = context.Request.Headers["Authorization"];
if (string.IsNullOrEmpty(auth) || !auth.StartsWith("Bearer ", System.StringComparison.OrdinalIgnoreCase))
{
await context.ChallengeAsync("oidce", new AuthenticationProperties {
RedirectUri = "/"
});
}
else
{
await next();
}
}
else
{
await next();
}
});
Now if the cookie expires it triggers the "ChallengeAsync" - that doesn't really work if the call originated from an AJAX request made from the browser. I thought since I had the context here that it would simply override the AJAX and make the browser start the round-trip.
Is there a way to say to the browser that "no, this isn't an AJAX-response, go where I tell you to"?
As Tseng pointed out in the comments I implemented almost to the letter.
app.Use(async (context, next) =>
{
if (!context.User.Identity.IsAuthenticated)
{
if (context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
// webapp will then do a location.reload() which triggers the auth
context.Response.StatusCode = 401;
}
else
{
string auth = context.Request.Headers["Authorization"];
if (string.IsNullOrEmpty(auth) || !auth.StartsWith("Bearer ", System.StringComparison.OrdinalIgnoreCase))
{
await context.ChallengeAsync();
}
else
{
await next();
}
}
}
else
{
await next();
}
});
The javascript application then catches the Ajax exception and checks if the status is 401 and simply does window.location.reload()
Not an elegant solution, will probably rewrite in the future but it solves the immediate problem.

ASP.NET Web API HttpContext Response is sent back before IOwinContext Response

We are using Owin middleware in an ASP.NET Web API 2 project hosted in IIS.
I am currently experiencing a strange phenomenon where the IOwinContext.Response.Body is not being written to, and actually, even when I have a break point set in the middleware after awake Next.Invoke(), and it gets hit, the response has already been sent back to the server even if I haven't continued yet.
When I look at the response body on the IOwinContext it is empty. However, I can get the response from the HttpContext.Response.Filter. When I use the HttpContext and hit the break point, then the response isn't sent back until I continue. Below is the current configuration method being used in our Startup.cs class.
public async void Configuration(IAppBuilder app)
{
try
{
// Global Config
var config = GlobalConfiguration.Configuration;
// configure dependency injection
UnityConfig.RegisterComponents();
// configure log for net
log4net.Config.XmlConfigurator.Configure();
// turn around all requests right here
app.Use(async (context, next) =>
{
if (context.Request.Path.ToString() == "/")
{
string text = "UP";
context.Response.StatusCode = 200;
context.Response.ReasonPhrase = text;
await context.Response.WriteAsync(text);
return;
}
await next.Invoke();
});
// Handle exceptions in the OWIN layer here
app.UseUncaughtExceptionHandler();
// add cors headers
app.Use(async (context, next) => { });
// some UI stuff
app.Use(async (context, next) => { });
// Log Request Metrics
app.UseLogRequestMetrics();
// Evaluate Partner Key
app.MapWhen(context => Regex.IsMatch(context.Request.Uri.PathAndQuery.ToLower(), #"/api"), newApp =>
{
#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>(); // On the response path back, the IOwinResponse body is already empty
});
WebApiConfig.Register(config);
app.UseWebApi(config); // It seems like I'm losing the response in here, but I don't really know
config.EnsureInitialized();
// Configure object mapping
AutoMapperConfig.Configure();
}
catch (Exception ex)
{
await LogForNetErrorLogger.LogError(ex);
}
}
I'm pretty sure my middleware is messed up, but the response is already gone before it gets back to the first of my middlewares (Middleware3) after the await Next.Invoke()
Any insight or thought provoking would be appreciated. Also, if this isn't enough information please let me know.
So, as in my post above, the problem, I thought, was the HttpResponse was being sent back before the IOwinResponse was. As it turns out, I completely overlooked the mapping section:
app.MapWhen(context => Regex.IsMatch(context.Request.Uri.PathAndQuery.ToLower(), #"/api"), newApp =>
{
#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>();
});
When you use app.Map() it branches the middleware. So, if the path matched "/api" it would branch. However, it was also still using the app.UseWebApi() component so that was why I had two different responses and why the response I was expecting wasn't written to the Middleware3 component's IOwinContext.
I fixed it by removing the app.MapWhen() method, changing it from this:
app.MapWhen(context => Regex.IsMatch(context.Request.Uri.PathAndQuery.ToLower(), #"/site"), newApp =>
{
#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>(); // On the response path back, the IOwinResponse body is already empty
});
to this:
#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>();
and putting this piece of code at the beginning of the middleware components Middleware1, Middleware2, Middleware3:
public override async Task Invoke(IOwinContext context)
{
if (!context.Request.Path.ToString().StartsWith("/api/"))
{
await Next.Invoke(context);
return;
}
// stuff I want to run if the above doesn't match
await Next.Invoke(context);
...
}
Well, at least the fix was simple, even if it took me three weeks to find it. If you want to read up on the IAppBuilder.MapWhen extension method, here is some documentation https://msdn.microsoft.com/en-us/library/owin.mapwhenextensions.mapwhen(v=vs.113).aspx.

Categories

Resources