.Net Core Middleware hitting multiple times on page request - asp.net-core

I am logging a user's audit to the database on every page click and I thought doing this in the middleware was acceptable (And good?) as it gets fired on every HTTP request. However, when I proceed to a new page, the code in the middleware (userService.AddUser()) is being hit 3 times and I am unsure why.
Here is the code:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IUserService userService)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
// My own code.
app.Use(async (context, next) =>
{
// The database insert
userService.AddUser();
await next.Invoke();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
I am probably missing some knowledge as of why this doesn't work.
Thanks

It's being called multiple times due to images not being found on said page.
In the console of the browser, a third party library cannot find an image which is calling a 404.
sort_both.png:1 Failed to load resource: the server responded with a
status of 404 ()
If this happens to you, I would check the console window in case images and or files are missing.

Related

How to set the redirect URI when using Microsoft sign-in in a .NET 5 application?

I have created a .NET 5 application with Microsoft sign-in based on this explanation.
It is working fine when running locally. However, something is going wrong when running the application in Amazon EKS. This became clear to me after reading error message I saw in the browser and after reading the network traffic.
This is how this looks like.
What becomes clear is that there is something wrong with "redirect_uri" (containing http instead of https). This is really frustrating as my application is using https. I use https when opening the application in my browser. It is important to mention that this does not occur when running the application locally on my laptop. What I hope for is that there is a simple way to set the "redirect_uri" property that is used in my code. In this way, I can guarantee that the right redirect uri is used.
Here is the source code I would like to change:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var configSettings = new ConfigSettings();
Configuration.Bind("ConfigSettings", configSettings);
services.AddSingleton(configSettings);
services.AddSingleton<IAuthResponseFactory, AuthResponseFactory>();
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
services.AddHealthChecks();
services.Configure<HealthCheckPublisherOptions>(options =>
{
options.Delay = TimeSpan.FromSeconds(2);
options.Predicate = (check) => check.Tags.Contains("ready");
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
{
Predicate = (check) => check.Tags.Contains("ready")
});
endpoints.MapHealthChecks("/health/live", new HealthCheckOptions());
});
}
So how do I change my source in a way that I can set the redirect uri correctly?
Looks like you need to enable header forwarding.
Step 1: configure the ForwardedHeadersOptions
services.Configure<ForwardedHeadersOptions>(options =>
{
options.RequireHeaderSymmetry = false;
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// TODO : it's a bit unsafe to allow all Networks and Proxies...
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
Step 2: UseForwardedHeaders in the public void Configure(IApplicationBuilder app, IHostingEnvironment env) method
app.UseForwardedHeaders();
Step 3: Only use UseHttpsRedirection for production
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// Forward http to https (only needed for local development because the Azure Linux App Service already enforces https)
app.UseHttpsRedirection();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
See How to set redirect_uri protocol to HTTPS in Azure Web Apps and .net Core X Forwarded Proto not working

gettting 401 on Hangfire with LocalRequestsOnlyAuthorizationFilter

We are trying to use hangfire with LocalRequestsOnlyAuthorizationFilter. We have deployed the application to IIS. When trying to access the hangfire dashboard from same machine where IIS is deployed, we are getting 401 on hangfire dashboard URL "/jobs". All we are trying to do here is allow to view the dashboard as long as request is coming from same machine where hangfire is deployed. Below is our config on startup.cs file
public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseHangfireDashboard("/jobs", new DashboardOptions()
{
Authorization = new[] { new LocalRequestsOnlyAuthorizationFilter() }
});
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHangfireDashboard();
});
backgroundJobs.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));
}
We checked both remote and local ip and both are same. Is there anything else we are missing here? Just to make sure application is running or not on IIS, we are added the another page and that page is working fine.
Change your Authorization to AuthorizationFilters,
app.UseHangfireDashboard("/jobs", new DashboardOptions()
{
AuthorizationFilters = new[] { new LocalRequestsOnlyAuthorizationFilter() }
});
Also, from this post check to make sure ASP.net is correctly installed and integrated pipeline is used for your application pool
This is also another good resource to go through in validating your IIS configuration

Route homepage to Index inside Areas?

I want to use Areas for my RazorPage 3.1 Core project. However, I can't seem to redirect the homepage from
http://localhost:<port> to http://localhost:<port>/Default/Index and the moment I use Areas and move my Pages folder into the Areas/Default/Pages I get an obvious 404 at my homepage. Every time I launch the project I get a 404 now for the homepage.
Or am I supposed to have 1 Pages folder outside of the Areas folder with the index as seen in the image below? That would be weird.
I tried everything I could find but I can't figure it out. I think it must be set somewhere in the Startup.cs:
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Default/Index", ""); // Or something?
});
and:
public IActionResult Get()
{
return RedirectToAction("Default/Index");
}
This didn't work for me:
https://www.learnrazorpages.com/advanced/areas#configuration
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/areas?view=aspnetcore-3.1#areas-with-razor-pages
Route homepage to Index inside Areas
It seems that you'd like to display index page under Default area folder while user access at the root URL of your website.
To achieve the requirement, you can try to do URL rewrite operation like below.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.Use(async (context, next) =>
{
if (context.Request.Path=="/")
{
context.Request.Path = "/Default/Index";
}
await next.Invoke();
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Test Result

ASP.net-core 3.0 - Is it possible to return custom error page when user is not in a policy?

I'm creating an intranet website and I'm having some trouble with the authentication part. I would like to limit the access for a controller to users in a specific Active Directory Roles. If the user is not in the specified Roles, then it should redirect him to a custom error page.
Windows authentication is enabled. I've tried the following solutions :
I created a custom policy in my ConfigureServices method inside my Startup.cs :
...
services.AddAuthorization(options =>
{
options.AddPolicy("ADRoleOnly", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireRole(Configuration["SecuritySettings:ADGroup"], Configuration["SecuritySettings:AdminGroup"]);
});
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
....
with inside my appsettings.json my active directory groups (not the one i'm really using of course) :
"SecuritySettings": {
"ADGroup": "MyDomain\\MyADGroup",
"AdminGroup": "MyDomain\\MyAdminGroup"
}}
and inside my Configure method :
...
app.UseAuthorization();
app.UseAuthentication();
app.UseStatusCodePagesWithReExecute("/Home/ErrorCode/{0}");
...
I have the following controller :
[Area("CRUD")]
[Authorize(Policy = "ADRoleOnly")]
public class MyController : Controller
I have a HomeController with the following method :
[AllowAnonymous]
public IActionResult ErrorCode(string id)
{
return View();
}
but when I debug my site, this method is never reached.
If I'm a user inside one of the specified roles of my policy, it's all working as expected.
But if I'm not a member of the roles, I'm redirected to the default navigator page.
I would like to redirect to a custom error page. I thought that was the purpose of
app.UseStatusCodePagesWithReExecute("/Home/ErrorCode/{0}");
It will generate a 403 statuscode when the policy fails,app.UseStatusCodePagesWithReExecute does not detect 403:
UseStatusCodePagesWithReExecute is not working for forbidden (403)
You could write a custom middleware to deal with it :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 403)
{
var newPath = new PathString("/Home/ErrorCode/403");
var originalPath = context.Request.Path;
var originalQueryString = context.Request.QueryString;
context.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
{
OriginalPathBase = context.Request.PathBase.Value,
OriginalPath = originalPath.Value,
OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
});
// An endpoint may have already been set. Since we're going to re-invoke the middleware pipeline we need to reset
// the endpoint and route values to ensure things are re-calculated.
context.SetEndpoint(endpoint: null);
var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
routeValuesFeature?.RouteValues?.Clear();
context.Request.Path = newPath;
try
{
await next();
}
finally
{
context.Request.QueryString = originalQueryString;
context.Request.Path = originalPath;
context.Features.Set<IStatusCodeReExecuteFeature>(null);
}
// which policy failed? need to inform consumer which requirement was not met
//await next();
}
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}

.MapWhen executing for all calls

I have a large already running application built on .net core 1.0.4. I have a need to add a micro api to this application, and am attempting to integrate a fairly simple http basic auth middleware into the pipeline only for calls to the api controller.
In my startup.csconfigure method, I have the following.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//run basic auth only on API calls
app.MapWhen(context => context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase), appBuilder =>
{
app.UseMiddleware<BasicAuthenticationMiddleware>();
app.UseMvc();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/site/error");
}
app.UseStaticFiles();
app.UseIdentity();
app.UseDefaultFiles();
app.UseStatusCodePages();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Site}/{action=Login}/{id?}");
});
}
It's my understanding that the pipeline would branch for all calls that start with /api into the Basic middle ware. My issue is that with this code, ALL calls regardless of the path are hitting the .MapWhen path, and essentially breaking the entire site.