app.UseDefaultFiles in Kestrel not doing anything? - c#

I have this in a Startup.cs file for a small project for a webserver hosting static files with Kestrel:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var configBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config.json");
var config = configBuilder.Build();
var options = new RewriteOptions()
.AddRedirectToHttps();
app.UseRewriter(options);
DefaultFilesOptions defoptions = new DefaultFilesOptions();
defoptions.DefaultFileNames.Clear();
defoptions.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(defoptions);
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), #"static")),
RequestPath = new PathString("")
});
loggerFactory.AddConsole(config.GetSection(key: "Logging"));
}
}
However, it doesn't try to load an index.html or anything. If I access it manually, it does indeed work.
Any ideas?
Thanks

Ideally your index.html should be under the web root path (wwwroot), however, if your file is under ContentRootPath\static (as it appears to be), you will need to change your code to specify the DefaultFilesOptions.FileProvider as follows:
PhysicalFileProvider fileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"static"));
DefaultFilesOptions defoptions = new DefaultFilesOptions();
defoptions.DefaultFileNames.Clear();
defoptions.FileProvider = fileProvider;
defoptions.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(defoptions);
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = fileProvider,
RequestPath = new PathString("")
});
Note: you are probably better off using IHostingEnvironment.ContentRootPath (env.ContentRootPath) rather than Directory.GetCurrentDirectory() on the first line (just in case you want to change the content root in your WebHostBuilder at some point).

Kudos to CalC for his insight, which got me closer to the answer for asp.net core 2.2. Here's what I ended up needing to do to serve a default document outside of the main web server root in Azure:
public void Configure(IApplicationBuilder app){...
// content is physically stored at /site/abc on an Azure Web App, not /site/wwwroot/abc
string path = Path.Combine(Directory.GetCurrentDirectory(), "abc");
PhysicalFileProvider fileProvider = new PhysicalFileProvider(path);
DefaultFilesOptions options = new DefaultFilesOptions
{
FileProvider = fileProvider,
RequestPath = "/ABC",
};
options.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(options);
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = "/ABC"
});
}
The key was using matching RequestPath and FileProvider values

Related

Protect Static Files with Authentication on ASP.NET Core

In my previous question, I asked a generic question how to add permission for static content. Here I want to be more precise.
In my project I added a folder under wwwroot to simplify the code, where I save the html files I want to protect. This folder is called infographics.
The properties for each file are:
Build Action: Content
Copy to Output Directory: Do not copy
Follow the instruction from the Microsoft documentation, I changed the Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.Configure<IdentityServerConfiguration>(Configuration.GetSection("IdentityServerConfiguration"));
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.Cookie.Name = ".my.Session";
options.IdleTimeout = TimeSpan.FromHours(12);
});
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
options.Cookie.Name = "my.dashboard";
})
.AddOpenIdConnect("oidc", options =>
{
IdentityServerConfiguration idsrv = Configuration.GetSection("IdentityServerConfiguration")
.Get<IdentityServerConfiguration>();
options.Authority = idsrv.Url;
options.ClientId = idsrv.ClientId;
options.ClientSecret = idsrv.ClientSecret;
#if DEBUG
options.RequireHttpsMetadata = false;
#else
options.RequireHttpsMetadata = true;
#endif
options.ResponseType = "code";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("roles");
options.Scope.Add("offline_access");
options.ClaimActions.MapJsonKey("role", "role", "role");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.SignedOutRedirectUri = "/";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
if (ctx.Context.Request.Path.StartsWithSegments("/infographics"))
{
ctx.Context.Response.Headers.Add("Cache-Control", "no-store");
if (!ctx.Context.User.Identity.IsAuthenticated)
{
// respond HTTP 401 Unauthorized with empty body.
ctx.Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
ctx.Context.Response.ContentLength = 0;
ctx.Context.Response.Body = Stream.Null;
// - or, redirect to another page. -
// ctx.Context.Response.Redirect("/");
}
}
}
});
app.UseRouting();
app.UseAuthorization();
app.UseCookiePolicy();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
What I expect is when the user asks for /infographics the OnPrepareResponse verifies the request and if the user is authenticated sees the page. But, after a lot of code changing, the result is always the same (on my local machine):
This localhost page can’t be found
I tried to add this code to map the folder html in the root of the project as infographics but without success.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "html")),
RequestPath = "/infographics"
});
Any ideas?
Update
This is working with not HTML files. I think the problem comes from the HTML file because they are static content for ASP.NET.
I put a breakpoint on the OnPrepareResponse and call the page infographics/index.html. The page is displayed (red arrow) and then the application stops on the breakpoint (blue arrow).
For any one else that ends up here searching for protecting secure static files.
For .NET Core 5. Documentation has been updated to include how to handle this
Per the documentation:
To serve static files based on authorization:
Store them outside of wwwroot.
Call UseStaticFiles, specifying a path, after calling UseAuthorization.
Set the fallback authorization policy.
Make sure to add a fallback policy as well:
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
See: Static file authorization
I would recommend to place that folder outside the wwwroot folder, which will remove the static file access to it.
You can then serve your files from a controller like so:
public IActionResult GetInfographic(string name)
{
var infographicPath = resolvePath(name);
return new FileStreamResult(new FileStream(infographicPath, FileMode.Open, FileAccess.Read), mime);
}
given this is a controller you can use the [Authorize] tag to secure it any way you'd like.

Share cookie .net Core 3 and Asp.net

Trying to share auth cookie by following the microsoft docs here: MS Docs
Heres my Startup.vb from the older Webforms project.
<Assembly: OwinStartup("Me", GetType(Startup))>
Public Class Startup
Public Sub Configuration(ByVal app As IAppBuilder)
Dim opt = New CookieAuthenticationOptions
opt.AuthenticationType = "Identity.Application"
opt.CookieName = ".SSO"
opt.LoginPath = New PathString("/Login.aspx")
opt.CookieDomain = "localhost"
opt.CookieHttpOnly = False
opt.CookieSecure = CookieSecureOption.SameAsRequest
Dim proc = DataProtectionProvider.Create(New DirectoryInfo("c:\Temp\DataKeys"), Function(s) s.SetApplicationName("MyApp")).CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "Cookies", "v2")
Dim shim = New DataProtectorShim(proc)
opt.CookieManager = New ChunkingCookieManager()
opt.TicketDataFormat = New AspNetTicketDataFormat(shim)
app.UseCookieAuthentication(opt)
End Sub
End Class
And here is the startup for .net core 3 app.
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
Environment = env;
}
public IWebHostEnvironment Environment { get; }
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor().AddHubOptions(o =>
{
o.MaximumReceiveMessageSize = 2000 * 1024 * 1024; // 10MB
});
services.AddSingleton<IConfiguration>(Configuration);
services.AddSingleton<IJwtHandler, JwtHandler>();
services.Configure<TokenSettings>(Configuration.GetSection("Token"));
services.AddSingleton<IWebHostEnvironment>(Environment);
services.AddHttpContextAccessor();
services.AddScoped<HttpContextAccessor>();
services.AddFileReaderService();
services.AddTelerikBlazor();
services.AddSweetAlert2();
services.AddSingleton<WeatherForecastService>();
services.Configure<AnimateOptions>(options =>
{
options.Animation = Animations.Fade;
options.Duration = TimeSpan.FromMilliseconds(200);
});
services.AddDataProtection()
.PersistKeysToFileSystem(new System.IO.DirectoryInfo(#"C:\Temp\DataKeys"))
.SetApplicationName("MyApp");
services.AddAuthentication("Identity.Application")
.AddCookie("Identity.Application", options =>
{
options.Cookie = new CookieBuilder
{
Domain = "localhost",
Name = ".SSO",
SameSite = SameSiteMode.Lax,
HttpOnly= false,
SecurePolicy = CookieSecurePolicy.SameAsRequest,
IsEssential = true
};
});
}
// 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("/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.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
I login to the legacy Webforms app, everything works fine. I try to navigate to the .net core 3 app, and it says I'm not authenticated, it does pass the cookie. I'm not sure what I'm doing wrong?
I did end up figuring this out for the most part.
On the .net Core 3 app, you can remove the 'DisableAutomaticKeyGeneration()' call if you plan on generating the keys from the .net core app.
var proc = DataProtectionProvider.Create(new DirectoryInfo(Configuration["SSO:KeyLocation"].ToString()), (builder) => { builder.SetApplicationName("MyApp").ProtectKeysWithDpapi().DisableAutomaticKeyGeneration(); })
.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "Cookies", "v2");
services.AddAuthentication("Identity.Application")
.AddCookie("Identity.Application", options =>
{
options.TicketDataFormat = new TicketDataFormat(proc);
options.SlidingExpiration = true;
options.Cookie = new CookieBuilder
{
Domain = Configuration["SSO:Domain"].ToString(),
Name = ".SSO",
SecurePolicy = CookieSecurePolicy.None,
IsEssential = true,
};
});
And on the .Net Framework app, You can remove 'ProtectKeysWithDpapi()', if the web apps are not running under the same Service account for the app pools.
Also, you need to make sure you have this version of nuget package installed on both apps,
Microsoft.AspNetCore.DataProtection v3.1.3
Dim opt = New CookieAuthenticationOptions
opt.AuthenticationType = "Identity.Application"
opt.CookieName = ".SSO"
opt.LoginPath = New PathString("/Login.aspx")
opt.CookieDomain = ConfigurationManager.AppSettings("SSODomain")
opt.SlidingExpiration = True
Dim proc = DataProtectionProvider.Create(New DirectoryInfo(ConfigurationManager.AppSettings("SSOKeyLocation")), Function(s) s.SetApplicationName("MyApp").SetDefaultKeyLifetime(TimeSpan.FromDays(9000)).ProtectKeysWithDpapi()).CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "Cookies", "v2")
Dim shim = New DataProtectorShim(proc)
opt.TicketDataFormat = New AspNetTicketDataFormat(shim)
app.UseCookieAuthentication(opt)
For localhost development/testing, just set the domain to 'localhost'

Asp.net core 3.0 - static files don't load

I just deployed a new asp.net core 3.0 project, but it seems most of the files are not loading, e.g. the boostrap, css files and lots of images. (AS the website is all over the place)
I looked through the project (root solution) and included them in my project. (Deleted the entire solution online and re-published it again and again ) even restarted VS.
here is my statup.cs
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"wwwroot"))
,
RequestPath = new PathString("/wwwroot")
});
app.UseHttpsRedirection();
app.UseStaticFiles();
But it did not change the problem
Here is a browser tools. Any advise ?
I think you have missed this in your program.cs
try adding like this
.UseContentRoot(Directory.GetCurrentDirectory())
like
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
and in startup.configure use UseDirectoryBrowser as
app.UseDirectoryBrowser(new DirectoryBrowserOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"wwwroot\images")),
RequestPath = new PathString("/MyImages")//this is the folder under
images
});
And add AddDirectoryBrowser extension method in Startup.ConfigureServices as
public void ConfigureServices(IServiceCollection services)
{
services.AddDirectoryBrowser();
}
and add like this in your startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseStaticFiles(); // For the wwwroot folder
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"wwwroot\images")),
RequestPath = new PathString("/MyImages")
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"wwwroot\images")),
RequestPath = new PathString("/MyImages")
});
}
and also add like this in your startup.configure as
public void Configure(IApplicationBuilder app)
{
app.UseDefaultFiles();
app.UseStaticFiles();
}
In my case I am using asp.net core 3.1, we can configure static file option by using the following code.In this code we have the file folder named "myfiles", in wwwroot static resource directory, I just want to access this folder by using another name "files" . For more asp.net core tutorial visit my blog website https://www.yogeshdotnet.com
In Asp.Net Core 3.1
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"wwwroot\myfiles")),
RequestPath = new PathString("/files")
});
In Asp.Net Core 2.1
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider (
Path.Combine(Directory.GetCurrentDirectory(), "myfile")), RequestPath =new PathString("/files")
});

how to use multiple folder into app.UseStaticFiles in .net core?

I want to get access to multiple folder locations from my web api to display image.
I can't change the folder locations (depending on devices on which I don't have right to modify anything).
for one of the folders I did:
string FolderToListen = Configuration["xxx:yyy"];
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(FolderToListen),
});
and now I would like to do:
string FolderToListen2= Configuration["xxx2:yyy2"];
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(FolderToListen),
FileProvider = new PhysicalFileProvider(FolderToListen2),
});
but it doesn't work.
Is there any way to pass multiple folders to UseStaticFiles ?
You can register UseStaticFolder twice:
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(FolderToListen),
});
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(FolderToListen2),
});
This answer is wonderful, localhost'ly, but when I push an .NET Core 3.1 app into Azure Web Apps it completely goes 500 on me.
Looking around the web it appears that duplicate entries are not allowed ... although this seems more like in Startup services.
I think I too would prefer a solution like,
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(FolderToListen),
FileProvider = new PhysicalFileProvider(FolderToListen2),
});
not that its possible, of course, but the duplicate entries simply don't seem to work.

Specifying default file name for asp.net core static folder

I currently have a generated index.html, js and other static files living in a folder and I'm marking that folder as a static folder (by adding the following in the Configure method in Startup.cs:
app.UseDefaultFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new Path.Combine(env.ContentRootPath, #"../build")),
RequestPath = new PathString("/app/")
});
Is there a way to set index.html as the default response for this */app route? Because right now localhost:5000/app/ returns a 404 while localhost:5000/app/index.html returns the index.html.
EDIT: I missed to mention that I did try using app.UseDefaultFiles() like mentioned in docs but it does not work for me. The server still returns a 404
One of the comments in that docs has clarified it:
Kieren_Johnstone
Featured May 22, 2017
The section, "Serving a default document" misses some vital
information. If you configure your UseStaticFiles to work off a
non-root RequestPath, you need to pass the same FileProvider and
RequestPath into both UseDefaultFiles and UseStaticFiles, it seems.
You can't always just call it as stated in the section.
So that means, you should write something like this to enable your specified folder to provide a default page:
app.UseDefaultFiles(new DefaultFilesOptions()
{
FileProvider = Path.Combine(env.ContentRootPath, #"../build")),
RequestPath = new PathString("/app/")
});
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = Path.Combine(env.ContentRootPath, #"../build")),
RequestPath = new PathString("/app/")
});
Use this:
public void Configure(IApplicationBuilder app)
{
// Serve my app-specific default file, if present.
DefaultFilesOptions options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
}
For more details follow this link:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files
and go to section: "Serving a default document"
from documentation:
Setting a default home page gives site visitors a place to start when
visiting your site. In order for your Web app to serve a default page
without the user having to fully qualify the URI, call the
UseDefaultFiles extension method from Startup.Configure as follows.
public void Configure(IApplicationBuilder app)
{
app.UseDefaultFiles();
app.UseStaticFiles(); // For the wwwroot folder
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"build")),
RequestPath = new PathString("/app")
});
}
UseDefaultFiles must be called before UseStaticFiles to serve the
default file.

Categories

Resources