5

Я уже знаю о безопасности на уровне пользователей и ролей в ASP.NET MVC. Но теперь мне нужно что-то более зернистое.Безопасность на основе документов в ASP.NET MVC

Предположим, у меня есть список документов, некоторые из которых разрешены для пользователя, а некоторые нет. Каждый документ имеет соответствующую запись в таблице документов в базе данных. Документы можно загрузить для просмотра, если у пользователя есть доступ к безопасности. Документы также могут быть добавлены, если у вас есть эта роль. Каждый документ имеет URL-адрес, и каждый список документов имеет URL-адрес.

Я бы хотел, чтобы система безопасности украшала список, чтобы пользователь видел только те документы, для которых он разрешен. Но мне также нужно аутентифицировать URL-запросы для этих списков и документов, так как нет ничего, что помешает пользователю закладок документа, к которому у них больше нет доступа, или просто введите URL-адрес в браузер.

Является ли встроенная модель безопасности на основе ролей подходящей для этого или нужна отдельная защита на основе таблиц? Могу ли я установить защиту в свой репозиторий, чтобы возвращаемые записи уже были обрезаны или были частью контроллера? Мне нужен атрибут безопасности для проверки запроса контроллера, или я должен просто поместить его в метод контроллера в качестве первых нескольких строк кода?

ответ

1

@Robert, я думаю, вы уже ответили на свой вопрос, когда сказали, что должны урезать их (до), чтобы они достигли представления. Таким образом, в вашей бизнес-логике, в качестве предпочтения по сравнению с хранилищем, вы можете захотеть сделать lamda, чтобы обрезать избыток, так сказать.

Мне кажется, я никогда не вернул бы какие-либо записи в представление, которое пользователю было запрещено видеть. Зачем увеличивать риск и трафик?

Что касается закладок, я думаю, что вам понадобится сделать некоторую бизнес-логику, не позволяющую им перейти к URL-адресу, когда доступ больше не существует.

Я думал, что контроллер был просто там, чтобы обслуживать данные на странице и не иметь никакой логики как таковой, поэтому я бы предпочел подход бизнес-уровня для этого, поскольку он кажется бизнес-правилом.

Возможно, это не так, как вы имели в виду, но если нет лучшего подхода, это тот, который я бы использовал.

+0

Похоже, вы одобряете подход, используя бизнес-логику, находящуюся в частичном классе DAL/ORM. Звучит ли это правильно? –

+0

Да, но это нечто более разрозненное. Хотя я не возражаю, подумав об этом, идея частичного в DAL, мой предпочтительный подход всегда заключался в экстраполяции этого на реальный бизнес-уровень. Конечно, этот слой будет ссылаться на объекты DAL, но он отделяет мою бизнес-логику от моей базы данных. Это просто звучит, как права доступа - это бизнес-правило, а не DAL. – griegs

+0

Мне нравится идея положить его в бизнес-логику; вы все равно можете скрыть проверку безопасности от контроллера, и вам нужно сделать это только один раз (он также работает для обрезки безопасности). –

1

Я попытаюсь объяснить, как я намеревался реализовать это в своем проекте. Требование аналогично вашему: у Пользователей есть Роли, у которых есть Разрешения, и все может измениться с определения Разрешения, списка Разрешений Роли и списка Ролей Пользователя и т. Д. Таким образом, в один момент возможно, что Пользователь имеет доступ к чему-то и в другом, если Администратор изменит что-то, у него нет доступа.

Прежде чем поставить код, я отвечу на ваши вопросы.

Нужно ли создавать отдельные, настольные системы безопасности?

Да

Могу ли я поставить безопасность в моем хранилище, так что возвращаемые записи уже обрезаны, или должны это быть частью контроллера?

-I думаю, что безопасность должна быть частью бизнес-логики, поэтому я бы поставил ее где-то между контроллером и хранилищем.

Нужен ли атрибут безопасности для проверить запрос контроллера?

В моем проекте я поместил его в атрибут, но иногда мне нужно получить к нему доступ с контроллера, но с тех пор я сохраняю логику безопасности на бизнес-уровне, я не думаю, что это проблема ,

Первый атрибут простой атрибут, который просто позволяет авторизованы пользователям выполнять действия:

public class LoggedUserFilterAttribute : ActionFilterAttribute 
{ 
    public bool Logged { get; set; } 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     if (!SessionManager.IsUserLogged) 
     { 
      filterContext.Result = new RedirectToRouteResult(GetRedirectToNotLoggedRouteValues()); 
      this.Logged = false; 
     } 
     else 
      this.Logged = true; 
    } 

    public RouteValueDictionary GetRedirectToNotAuthorizedRouteValues() 
    { 
     RouteValueDictionary routeValues = new RouteValueDictionary(); 
     routeValues.Add("action", "NotAuthorized"); 
     routeValues.Add("controller", "Authorization"); 
     return routeValues; 
    } 
    public RouteValueDictionary GetRedirectToNotLoggedRouteValues() 
    { 
     RouteValueDictionary routeValues = new RouteValueDictionary(); 
     routeValues.Add("action", "NotLogged"); 
     routeValues.Add("controller", "Authorization"); 
     return routeValues; 
    } 
} 

, а затем у меня есть, например, атрибут, который позволяет только суперпользователи получить к нему доступ:

public class SuperUserFilterAttribute : LoggedUserFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     base.OnActionExecuting(filterContext); 

     if (Logged) 
     { 
      MyBaseController controller = filterContext.Controller as MyBaseController; 
      if (controller == null) 
       throw new Exception("Please use MyBaseController instead of built in Controller"); 

      User loggedUser = controller.Model.UserBO.GetUserByID(SessionManager.LoggedUser.UserID); 

      if(!loggedUser.IsSuperUser) 
      { 
       filterContext.Result = new RedirectToRouteResult(GetRedirectToNotAuthorizedRouteValues()); 
      } 
     } 
    } 
} 

MyBaseController - это класс, который наследует Controller и имеет экземпляр класса Model, который представляет контейнер для бизнес-объектов. В случае действия органа управления контроллером я проверяю права пользователей на текущий объект и в зависимости от этого я возвращаю надлежащий вид:

[LoggedUserFilter] 
    public ActionResult LoadSomeEntity(int customerServiceID,int entityID) 
    { 
     UserRights userPermissionsView = Model.SecurityBO.GetUsersRightsOnEntity(SessionManager.LoggedUser.UserID, entityID); 

     if(userPermissionsView.Write) 
      return View("EditEntity",Model.EntityBO.GetEntityByID(entityID)); 
     if(userPermissionsView.Read) 
      return View("ViewEntity",Model.EntityBO.GetEntityByID(entityID)); 

     return View("NotAuthorized");  
    } 

p.s. Я не уверен, могу ли я что-нибудь предложить кому-то, у которого, очевидно, гораздо больше опыта, чем я :), поэтому, если я спам, я прошу прощения за это.

+0

Спасибо за ответ. У вас есть правильная идея; Я видел шаблон Attribute, поскольку он применяется к аутентификации пользователей и ролей. Я видел, как кто-то еще задал вопрос об использовании атрибутов для обеспечения безопасности на основе таблиц. Проблема с этим подходом заключается в том, что вам необходим доступ к параметрам URL, чтобы сделать это правильно. Поскольку атрибут не имеет доступа к параметрам метода контроллера, вам нужно пройти через некоторые обручи, чтобы их получить. –

+0

Я вижу, AuthorizeAttribute в методе OnAuthorize не имеет доступа к параметрам метода контроллера, но ActionFilterAttribute в OnActionExecuting, который я использовал, имеет свойство filterContext.ActionParameters, возвращающее IDictionary , где key является параметром имя и значение - это значение, переданное методу. –

+0

Это хорошее наблюдение, но это просто кажется слишком далеким для моего вкуса. Так как я все равно собираюсь получать данные из своей модели, я могу просто защитить ее там. Если у пользователя нет доступа к определенным записям, они просто не будут отображаться в списке, и если одна запись будет получена для подробного представления, я могу проверить нуль и перенаправить. –

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