3

我有一个 MVC 5 应用程序,它允许用户下载存储在数据库中的文件。我正在使用 FileContentResult 操作方法来执行此操作。

我可以在整个应用程序中限制对该方法的访问,但聪明的用户可以找出操作 URL 并将类似这样的内容 (localhost:50000/Home/FileDownload?id=13) 粘贴到他们的浏览器中,并有权通过以下方式下载任何文件只是改变参数。

我想限制用户这样做。仅允许管理员角色和具有只能通过数据库调用确定的特定权限的用户下载文件。

我正在寻找的是,如果用户使用 URL 下载文件并且没有适当的权限,我想通过消息重定向用户。

我想做类似下面的代码或类似的事情,但我收到以下错误:无法将类型'System.Web.Mvc.RedirectToRouteResult'隐式转换为'System.Web.Mvc.FileContentResult'

我知道我不能在这里使用 return RedirectToAction("Index") ,只是寻找一些关于如何处理这个问题的想法。

    public FileContentResult FileDownload(int id)
    {
        //Check user has file download permission
        bool UserHasPermission = Convert.ToInt32(context.CheckUserHasFileDownloadPermission(id)) == 0 ? false : true;

        if (User.IsInRole("Administrator") || UserHasPermission)
        {
            //declare byte array to get file content from database and string to store file name
            byte[] fileData;
            string fileName;
            //create object of LINQ to SQL class

            //using LINQ expression to get record from database for given id value
            var record = from p in context.UploadedFiles
                         where p.Id == id
                         select p;
            //only one record will be returned from database as expression uses condtion on primary field
            //so get first record from returned values and retrive file content (binary) and filename
            fileData = (byte[])record.First().FileData.ToArray();
            fileName = record.First().FileName;
            //return file and provide byte file content and file name

            return File(fileData, "text", fileName);
        }
        else
        {
            TempData["Message"] = "Record not found";

            return RedirectToAction("Index");
        }           
    }
4

1 回答 1

8

由于FileContentResultRedirectToRouteResult都继承自ActionResult,因此只需使用ActionResult而不是FileContentResult您的操作的返回类型:

public ActionResult FileDownload(int id)
{
    if(IsUserCanDownloadFile()) // your logic here
    {
        // fetch the file
        return File(fileData, "text", fileName);
    }
    return RedirectToAction("Index");

}

或者,如果您更喜欢属性,您可以编写自己的授权属性来检查权限:

public class FileAccessAttribute : AuthorizeAttribute
{
    private string _keyName;

    public FileAccessAttribute (string keyName)
    {
        _keyName = keyName;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        // imagine you have a service which could check the Permission
        return base.AuthorizeCore(httpContext) 
            || (this.ContainsKey
                && _permissionService.CanDownload(httpContext.User.Identity.GetUserId(),
                    int.Parse(this.KeyValue.ToString()));
    }

    private bool ContainsKey
    {
        get
        {
            // for simplicity I just check route data 
            // in real world you might need to check query string too 
            return ((MvcHandler)HttpContext.Current.Handler).RequestContext
                .RouteData.Values.ContainsKey(_keyName);
        }
    }
    private object KeyValue
    {
        get
        {
            return ((MvcHandler)HttpContext.Current.Handler)
                .RequestContext.RouteData.Values[_keyName];
        }
    }
}

现在您可以在您的操作上装饰自定义属性:

[FileAccess("id", Roles ="Administrator")]
public FileContentResult FileDownload(int id)
{
    // fetch the file
    return File(fileData, "text", fileName);
}
于 2016-01-31T16:20:14.270 回答