Reputation: 2811
I am trying to do simple protection of a folder inside my web application. From the documentation seems very straight forward. Yet, it does not work for me.
I have a razor page with a folder called keys, with some text files there. From the docs:
I have tried:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options => {
options.Conventions.AuthorizeFolder("/keys");
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
....
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
Yet, once I start the application and I type on the browser:
https://localhost:44312/keys/clear.txt
The server is definitely sending back the page. Any clues?
Upvotes: 0
Views: 546
Reputation: 14640
Your comments under Cameron's answer have confused me a bit, so my answer may not be what you want to do.
Anyway, you can use app.UseStaticFiles()
to add middleware to protect that folder. As it's middleware, you need to insert it into the correct place in your pipeline for it to work. Here is the complete Configure
method in Startup.cs
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
// Notice that this is the second time we're calling UseStaticFiles().
// The first call is to configure CSS and things to be served.
// This is deliberately called after UseAuthentication().
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
if (ctx.Context.Request.Path.StartsWithSegments("/keys"))
{
// As the files are sensitive, don't cache a response.
ctx.Context.Response.Headers.Add("Cache-Control", "no-store");
if (!ctx.Context.User.Identity.IsAuthenticated)
{
ctx.Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
ctx.Context.Response.ContentLength = 0;
ctx.Context.Response.Body = Stream.Null;
}
}
},
// It's the combination of the `FileProvider` and `RequestPath` that
// maps the `MyKeys` physical folder to the `/keys` path.
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "MyKeys")),
RequestPath = "/keys"
});
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
In the example above, MyKeys
is a folder at the root of your project, and /keys
is the path used to request a file:
ProjectName
| wwwroot
| css
| etc
| Pages
| your razor pages
| MyKeys
| clear.txt
If the user is not authenticated, they will receive a 401 response. We deliberately do not cache the results, as the files are sensitive. You could, of course, do something more here, such as requiring a user to have a particular role, or redirecting them if they're not signed in. It's up to you.
Upvotes: 1
Reputation: 9789
The documentation mentions protecting routes in a folder handled by ASP.NET Core and not files on the filesystem. If you need to protect a resource, then you should write a resource handler to serve the file and protect the route and/or controller.
It should be something like this:
[Authorize]
public ResourceController : ControllerBase {
// Other Protected Resources
[HttpGet("keys/clear")]
public IActionResult Clear() {
var file = Path.Combine("secure/path", "clear.txt");
return PhysicalFile(file, "text/plain");
}
}
Note, since you are using a resource handler, you can move the clear.txt file to another directory that is not publicly accessible. It will need to be readable by your application user.
If the application is running in IIS, then the folder will need to have read permissions for the IIS Application Pool Identity. If it is running on Linux, then you'll need to grant read permissions to the user that is running the server.
Upvotes: 0