ASP.NET MVC中的模拟

时间:2010-04-15 12:48:40

标签: asp.net-mvc security impersonation

我有一个需要从安全位置读取文件的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:\项目\上传\ 1 \ aa2bcbe7-ea99-499d-ADD8-c1fdac561b0e \无标题   2.csv'被拒绝。

我想将文件结果与路径一起使用,当我已经“撤消”模拟时,尝试稍后在请求管道中打开文件。

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

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

提前致谢。

2 个答案:

答案 0 :(得分:4)

您可以尝试编写自定义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");

答案 1 :(得分: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();