Я попытаюсь объяснить, как я намеревался реализовать это в своем проекте. Требование аналогично вашему: у Пользователей есть Роли, у которых есть Разрешения, и все может измениться с определения Разрешения, списка Разрешений Роли и списка Ролей Пользователя и т. Д. Таким образом, в один момент возможно, что Пользователь имеет доступ к чему-то и в другом, если Администратор изменит что-то, у него нет доступа.
Прежде чем поставить код, я отвечу на ваши вопросы.
Нужно ли создавать отдельные, настольные системы безопасности?
Да
Могу ли я поставить безопасность в моем хранилище, так что возвращаемые записи уже обрезаны, или должны это быть частью контроллера?
-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. Я не уверен, могу ли я что-нибудь предложить кому-то, у которого, очевидно, гораздо больше опыта, чем я :), поэтому, если я спам, я прошу прощения за это.
Похоже, вы одобряете подход, используя бизнес-логику, находящуюся в частичном классе DAL/ORM. Звучит ли это правильно? –
Да, но это нечто более разрозненное. Хотя я не возражаю, подумав об этом, идея частичного в DAL, мой предпочтительный подход всегда заключался в экстраполяции этого на реальный бизнес-уровень. Конечно, этот слой будет ссылаться на объекты DAL, но он отделяет мою бизнес-логику от моей базы данных. Это просто звучит, как права доступа - это бизнес-правило, а не DAL. – griegs
Мне нравится идея положить его в бизнес-логику; вы все равно можете скрыть проверку безопасности от контроллера, и вам нужно сделать это только один раз (он также работает для обрезки безопасности). –