【问题标题】:Impersonation in ASP.NET MVCASP.NET MVC 中的模拟
【发布时间】:2011-02-08 08:57:28
【问题描述】:

我有一个 Action 需要从安全位置读取文件,所以我必须使用模拟来读取文件。

此代码有效:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult DirectDownload(Guid id)
{
    if (Impersonator.ImpersonateValidUser())
    {
        try
        {
            var path = "path to file";
            if (!System.IO.File.Exists(path))
            {
                return View("filenotfound");
            }

            var bytes = System.IO.File.ReadAllBytes(path);
            return File(bytes, "application/octet-stream", "FileName");
        }
        catch (Exception e)
        {
            Log.Exception(e);
        }finally
        {
            Impersonator.UndoImpersonation();
        }
    }
    return View("filenotfound");
}

上述代码的唯一问题是我必须将整个文件读入内存,而且我要处理非常大的文件,所以这不是一个好的解决方案。但是如果我替换这两行:

var bytes = System.IO.File.ReadAllBytes(path);
return File(bytes, "application/octet-stream", "FileName");

用这个:

return File(path, "application/octet-stream", "FileName");

它不起作用,我收到错误消息:

访问路径 'c:\projects\uploads\1\aa2bcbe7-ea99-499d-add8-c1fdac561b0e\Untitled 2.csv' 被拒绝。

我猜想使用带有路径的文件结果,稍后在我已经“撤消”模拟时尝试在请求管道中打开文件。

请记住,模拟代码有效,因为我可以读取字节数组中的文件。我想做的是将文件流式传输到客户端。

知道如何解决这个问题吗?

提前致谢。

【问题讨论】:

    标签: asp.net-mvc security impersonation


    【解决方案1】:

    我喜欢Darin的回答,但是它跳过了模拟逻辑,并且在IIS 7中抛出了一个错误...

    所以,我使用 Nuget Package SimpleImpersonation 尽可能地添加了模拟代码。

    此外,为了防止出现无效句柄错误,对 IIS 7 进行了一些更改。

    public class ImpersonatingFileResult : FilePathResult
    {
        public ImpersonatingFileResult(string fileName, string contentType)
            : base(fileName, contentType)
        { }
    
        protected override void WriteFile(HttpResponseBase response)
        {
            using (SimpleImpersonation.Impersonation.LogonUser(domain: "SomeDomain", username: "SomeUser", password: "SomePassword", logonType: SimpleImpersonation.LogonType.NewCredentials))
            {
                response.Clear();
                response.ContentType = base.ContentType;
                response.AddHeader("Content-Disposition", "attachment; filename=" + System.IO.Path.GetFileName(base.FileName));
                response.TransmitFile(FileName);
                response.Flush();
            }
        }
    

    然后从控制器中使用它:

            return new ImpersonatingFileResult(someFilePath, "Application/pdf");
    

    以上是下载文件,但如果要显示,则需要指定“内联”。

                response.Clear();
                response.ContentType = base.ContentType;
                response.AddHeader("Content-Disposition", "inline; filename=\"" + System.IO.Path.GetFileName(base.FileName) + "\"");
                response.TransmitFile(FileName);
                response.Flush();
    

    【讨论】:

      【解决方案2】:

      您可以尝试编写自定义FilePathResult

      public class ImpersonatingFileResult : FilePathResult
      {
          public ImpersonatingFileResult(string fileName, string contentType) 
              : base(fileName, contentType)
          { }
      
          protected override void WriteFile(HttpResponseBase response)
          {
              // TODO : Start impersonation
              response.TransmitFile(FileName);
              // TODO : Rollback impersonation
          }
      }
      

      在你的控制器中:

      return new ImpersonatingFileResult(path, "application/octet-stream");
      

      【讨论】:

      • 效果很好。我对其进行了一些更改,因为我遇到了异常... Impersonator.ImpersonateValidUser(); response.WriteFile(FileName); response.Flush();响应。结束(); Impersonator.UndoImpersonation();
      • 是的,这是一个好的开始。但是,它会在某些版本的 IIS 中抛出“无效句柄”错误,这些错误是基于提供文件(而不是基于模拟)。
      猜你喜欢
      • 1970-01-01
      • 2010-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      • 2010-11-02
      相关资源
      最近更新 更多