2016-01-31 2 views
1

У меня есть приложение MVC 5, которое позволяет пользователям загружать файлы, которые хранятся в базе данных. Для этого я использую метод действия FileContentResult.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"); 
     }   
    } 

ответ

3

Так как FileContentResult и RedirectToRouteResult унаследованы от 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]; 
     } 
    } 
} 

Теперь вы можете украсить обычай a ttribute о ваших действиях:

[FileAccess("id", Roles ="Administrator")] 
public FileContentResult FileDownload(int id) 
{ 
    // fetch the file 
    return File(fileData, "text", fileName); 
} 
+0

Спасибо Сэм! Это отличный ответ, и я буду работать над внедрением атрибута authorize для проверки разрешений. – Cesar

Смежные вопросы