在 ASP.NET Core 上通过身份验证保护静态文件

Enr*_*ico 6 c# asp.net-core

在上一个问题中,我问了一个通用问题如何添加静态内容的权限。在这里我想说得更准确一些。

\n

在我的项目中,我添加了一个文件夹wwwroot来简化代码,我在其中保存要保护的 html 文件。该文件夹称为infographics

\n

在此输入图像描述

\n

每个文件的属性是:

\n
    \n
  • 构建操作:内容
  • \n
  • 复制到输出目录:不复制
  • \n
\n

在此输入图像描述

\n

按照Microsoft文档的说明,我更改了Startup.cs

\n
public class Startup\n{\n    public Startup(IConfiguration configuration)\n    {\n        Configuration = configuration;\n    }\n\n    public IConfiguration Configuration { get; }\n\n    // This method gets called by the runtime. Use this method to add services to the container.\n    public void ConfigureServices(IServiceCollection services)\n    {\n        services.AddControllersWithViews();\n        services.Configure<IdentityServerConfiguration>(Configuration.GetSection("IdentityServerConfiguration"));\n\n        services.AddDistributedMemoryCache();\n\n        services.AddSession(options =>\n        {\n            options.Cookie.Name = ".my.Session";\n            options.IdleTimeout = TimeSpan.FromHours(12);\n        });\n\n        services.AddAuthentication(options =>\n        {\n            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;\n            options.DefaultChallengeScheme = "oidc";\n        })\n        .AddCookie(options =>\n        {\n            options.ExpireTimeSpan = TimeSpan.FromMinutes(30);\n            options.Cookie.Name = "my.dashboard";\n        })\n        .AddOpenIdConnect("oidc", options =>\n        {\n            IdentityServerConfiguration idsrv = Configuration.GetSection("IdentityServerConfiguration")\n                                                .Get<IdentityServerConfiguration>();\n            options.Authority = idsrv.Url;\n            options.ClientId = idsrv.ClientId;\n            options.ClientSecret = idsrv.ClientSecret;\n\n            #if DEBUG\n            options.RequireHttpsMetadata = false;\n            #else\n            options.RequireHttpsMetadata = true;\n            #endif\n\n            options.ResponseType = "code";\n\n            options.Scope.Clear();\n            options.Scope.Add("openid");\n            options.Scope.Add("profile");\n            options.Scope.Add("email");\n            options.Scope.Add("roles");\n            options.Scope.Add("offline_access");\n\n            options.ClaimActions.MapJsonKey("role", "role", "role");\n\n            options.GetClaimsFromUserInfoEndpoint = true;\n            options.SaveTokens = true;\n\n            options.SignedOutRedirectUri = "/";\n\n            options.TokenValidationParameters = new TokenValidationParameters\n            {\n                NameClaimType = JwtClaimTypes.Name,\n                RoleClaimType = JwtClaimTypes.Role,\n            };\n        });\n    }\n\n    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n    {\n        if (env.IsDevelopment())\n        {\n            app.UseDeveloperExceptionPage();\n        }\n        else\n        {\n            app.UseExceptionHandler("/Home/Error");\n            app.UseHsts();\n        }\n        app.UseHttpsRedirection();\n\n        app.UseAuthentication();\n\n        app.UseStaticFiles(new StaticFileOptions\n        {\n            OnPrepareResponse = ctx =>\n            {\n                if (ctx.Context.Request.Path.StartsWithSegments("/infographics"))\n                {\n                    ctx.Context.Response.Headers.Add("Cache-Control", "no-store");\n\n                    if (!ctx.Context.User.Identity.IsAuthenticated)\n                    {\n                        // respond HTTP 401 Unauthorized with empty body.\n                        ctx.Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;\n                        ctx.Context.Response.ContentLength = 0;\n                        ctx.Context.Response.Body = Stream.Null;\n\n                        // - or, redirect to another page. -\n                        // ctx.Context.Response.Redirect("/");\n                    }\n                }\n            }\n        });\n\n        app.UseRouting();\n\n        app.UseAuthorization();\n\n        app.UseCookiePolicy();\n        app.UseSession();\n\n        app.UseEndpoints(endpoints =>\n        {\n            endpoints.MapControllerRoute(\n                name: "default",\n                pattern: "{controller=Home}/{action=Index}/{id?}");\n        });\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我期望的是当用户要求/infographics验证OnPrepareResponse请求并且用户通过身份验证时会看到该页面。但是,经过大量代码更改后,结果始终相同(在我的本地计算机上):

\n
\n

无法找到此本地主机页面\xe2\x80\x99

\n
\n

我尝试添加此代码来映射html项目根目录中的文件夹,infographics但没有成功。

\n
app.UseStaticFiles(new StaticFileOptions\n{\n    FileProvider = new PhysicalFileProvider(\n        Path.Combine(env.ContentRootPath, "html")),\n    RequestPath = "/infographics"\n});\n
Run Code Online (Sandbox Code Playgroud)\n

有任何想法吗?

\n

更新

\n

这不适用于HTML文件。我认为问题出在 HTML 文件上,因为它们是 ASP.NET 的静态内容。

\n

我在 上放置了一个断点OnPrepareResponse并调用该页面infographics/index.html。显示页面(红色箭头),然后应用程序在断点处停止(蓝色箭头)。

\n

在此输入图像描述

\n

Ant*_*hik 0

我建议将该文件夹放置在 wwwroot 文件夹之外,这将删除对其的静态文件访问。

然后,您可以从控制器提供文件,如下所示:

public IActionResult GetInfographic(string name)
{
    var infographicPath = resolvePath(name);
    return new FileStreamResult(new FileStream(infographicPath, FileMode.Open, FileAccess.Read), mime);
}
Run Code Online (Sandbox Code Playgroud)

鉴于这是一个控制器,您可以使用[Authorize]标签以任何您想要的方式保护它。