【问题标题】:How do I serve static files only to authorized users?如何仅向授权用户提供静态文件?
【发布时间】:2016-08-15 00:41:52
【问题描述】:

我有一组 Excel 电子表格,我想在我的 ASP.NET 5 web 应用程序中仅向授权用户提供这些电子表格。

  1. 我应该将文件存储在哪里?我假设在 wwwroot 中(例如 wwwroot/files)。
  2. 如果在 wwwroot 中,我如何只允许授权用户访问? (我想将它们作为来自控制器的 [Authorize] FileResult 提供,但这仍然会使文件保持打开状态,以便通过我相信的 URL 直接访问。)
  3. 如何通过控制器中的 FileResult 操作引用 wwwroot 中的位置?

非常感谢!

【问题讨论】:

    标签: c# asp.net-core asp.net-core-staticfile


    【解决方案1】:

    在检索文件时进行身份验证检查:

            app.UseStaticFiles(new StaticFileOptions()
            {
                OnPrepareResponse = (context) =>
                {
                    if (!context.Context.User.Identity.IsAuthenticated && context.Context.Request.Path.StartsWithSegments("/excelfiles"))
                    {
                        throw new Exception("Not authenticated");
                    }
                }
            });
    

    【讨论】:

    • 这只有在使用的身份验证方案是默认身份验证方案时才有效,否则HttpContext.User 将不会更新(请参阅this issue)。
    【解决方案2】:

    如果您有一个登录表单 (Login.html),一个简单的解决方案是如果用户未通过身份验证并且他正在请求受保护的资源(/protected 文件夹下的文件),则将用户重定向到登录页面。在 Startup.cs 中,在 Configure 方法中插入以下代码:

    app.Use(async (context, next) =>
    {
        if (!context.User.Identity.IsAuthenticated && context.Request.Path.StartsWithSegments("/protected"))
        {
            context.Response.Redirect("/Login.html");
            return;
        }
        await next.Invoke();
    });
    

    【讨论】:

    • 但是如何确保 /wwwroot 下的文件受到保护?
    • 如果您只是删除路径上的控件,则一切都受到保护: if (!context.User.Identity.IsAuthenticated ) {...
    • 这只有在使用的身份验证方案是默认身份验证方案时才有效,否则HttpContext.User 将不会更新(请参阅this issue)。
    • Asp.Net Core 中有一个授权/身份验证子系统也处理登录/注销过程,手动重定向到登录页面是一种不好的做法。
    【解决方案3】:

    是的,他们应该进入wwwroot。目前没有内置的方法来保护wwwroot 目录。但是创建一个中间件模块来完成它非常简单。有一个简单易学的教程here

    如果您不熟悉开发中间件,我发布了一个 GitHub 项目,该项目展示了如何通过三个简单的步骤创建中间件。您可以下载项目here

    您不需要控制器来访问静态文件。

    【讨论】:

    • 太棒了。谢谢你。调查它。 (我只使用一个动作,因为我想在下载文件时发送通知。)
    • 或者您可以将它们放在 wwwroot 的外部,静态文件中间件不会接触到这些位置。就像一个很好的旧 App_Data 文件夹(诚然,您必须自己创建)
    • @Gabe - 您可以将该功能添加到您的中间件中。也许将我的帖子标记为已接受的答案。 :-)
    • 这就像一个魅力。我从您链接的教程中遇到的唯一问题是确保在 startup.cs/Configure 中对中间件的引用在 app.UseIdentity() 之后,但仍在 app.UseStaticFiles() 之前。
    • 实际上让我更清楚一点,您绝对应该将它们放在 wwwroot 下,因为静态文件中间件可能会为它们提供服务,因为它的本意是它可以理解的 wwwroot 下的任何文件。如果你搞乱了你的中间件顺序,把东西放在 wwwroot 下是一个巨大的信息泄露风险。
    【解决方案4】:

    这是一个非常简单的示例,但可以更改它以检查特定角色,并且可以将代码移出 Startup.cs 以获得更大的灵活性。

    app.Use(async (context, next) =>
                   {
                       if (!context.User.Identity.IsAuthenticated
                           && context.Request.Path.StartsWithSegments("/excelfiles"))
                       {
                           throw new Exception("Not authenticated");
                       }
                       await next.Invoke();
                   });
    

    【讨论】:

    • 使用context.Response.StatusCode = 403而不是抛出异常可能会更好。
    • 我认为这取决于情况。在我的应用程序中,异常被捕获、记录,然后显示一个通用错误页面。对于 API,我会返回 403。
    • 这只有在使用的身份验证方案是默认身份验证方案时才有效,否则HttpContext.User 将不会更新(请参阅this issue)。
    • @Dominus.Vobiscum 相信是没有正确配置中间件(Authentication middleware)的问题。应始终指定身份验证方案(默认或不指定)。默认只是一个后备,但始终应该配置/注册/指定一个方案。 HttpContext.User 是开始进行身份验证/授权的非常重要的中心。
    【解决方案5】:

    在.net core中创建一个与wwwroot同级的专用目录www,并使用如下代码:

    public HomeController(IHostingEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
    }
    
    [Authorize(Roles = "SomeRole")]
    public IActionResult Performance()
    {
        return PhysicalFile(Path.Combine(_hostingEnvironment.ContentRootPath,
                                         "www", "MyStaticFile.pdf"), "application/pdf");
    }
    

    基于以下答案(针对 .netCore):static file authorization

    【讨论】:

    • 请注意,上述操作可以由视图请求。例如说 /Home/Performance 返回一个图像/png。另一个 Action - 一种 Home/ParentPerformance,可以以标准方式返回 View(),并且在视图中您可以引用受保护的静态资源。例如:<img src="~/home/performance" style="width:100%;background:white;" /> 这样做的好处是您仍然可以使用共享的 _Layout 菜单系统和外观提供 HTML 信封,同时仍然保持静态文件的安全性。
    • 顺便说一句,我直到最近才提供PDF,才发现Android上的pdf体验很糟糕,强制下载/取消,最终导致用户无法获得流畅的体验,不像IOS,包括一些缩小屏幕边界。简而言之,不是你所期望的。从那时起,我使用InkScape 将PDF 导出为PNG,这与上面提到的html 中的<img> 完全一致。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    相关资源
    最近更新 更多