Как структурировать безопасность дочерних объектов, когда пользователь имеет доступ только к родительскому

#security #asp.net-mvc-3 #model-view-controller

#Безопасность #asp.net-mvc-3 #модель-представление-контроллер

Вопрос:

У меня есть структура базы данных, похожая на следующую:

 User
----
Id
Name

UserCustomerLink
----------------
UserId
CustomerId

Customer
--------
Id
Name

Address
-------
Id
CustomerId
Address1

Invoice
-------
Id
AddressId
Number
  

Это asp.net сайт mvc, чтобы пользователь мог перейти по адресу, подобному http://localhost/invoice/details/1 , который вернет счет с идентификатором 1.

Пользователь должен войти в систему и быть назначен клиенту (через таблицу UserCustomerLink), которому принадлежит счет (через адрес).

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

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

Меня беспокоит количество запросов к базе данных, которые будут выполнены для поиска этой информации, и я ищу эффективный метод. Это упрощенный взгляд на структуру, и некоторые дочерние свойства имеют глубину более 3.

В примечании к сайту я сначала использую код Entity Framework, поэтому, если есть способ создать сопоставление, которое включает идентификатор клиента в объект Invoice, это может потенциально решить эту проблему.

Ответ №1:

Нет причин совершать два обращения к базе данных. Вы можете использовать объединения и выполнять один select. Все ваши таблицы имеют внешние ключи, которые связывают записи. Когда запрос возвращается, вы проверяете, связан ли пользователь с этим счетом. Вы могли бы сделать то же самое с LINQ

 SELECT 
    i.*,
    c.Name
FROM 
    INVOICE i JOIN 
    Address a JOIN
        on i.addressId = a.id
    Customer c JOIN
        on a.customerID = c.id
    UserCustomerLink ucl join
        on c.id = ucl.CustomerId
    User u
        on ucl.Userid = User.id
WHERE 
    i.Id = @invoiceId
  

Комментарии:

1. Это то, что я в конечном итоге сделал, просто подумал, есть ли «более аккуратный» способ, который не требует такого количества объединений, но, кажется, выполняется достаточно быстро.

Ответ №2:

Посмотрите на атрибут авторизации. Вы могли бы распределить своих пользователей по ролям, а затем позволить фреймворку проверять за вас.

 [Authorize(Roles="AllowedUser")]
public ViewResult GetInvoies()
{
   return View();
}
  

Комментарии:

1. То, что вы описываете, — это безопасность на основе ролей, которой это не является. Поскольку пользователь может иметь доступ более чем к одному объекту, дело не в ролях, а в правах доступа, которые различаются у каждого пользователя.