Дункан,
Это то, с чем я сталкиваюсь в каждом приложении.Вот некоторый контекст: я работаю на одном факультете в крупном университете, поэтому нам приходится иметь дело с несколькими источниками данных.Большинство наших приложений имеют защиту, которая объединяет университетские «центральные ИТ» службы безопасности, такие как централизованная аутентификация и активный каталог, а также «доморощенные» роли и разрешения.
Наши приложения должны представлять разные представления и действия для разных пользователей на основе данных как в «доморощенных» приложениях (используемых внутри нашего отдела), так и данных предприятия.
Наш подход: после осмотраЧестно говоря, и нигде не найдя хорошего решения этой проблемы, я в итоге написал основу безопасности для нашего использования.Я мог бы также пойти дальше и описать, что здесь происходит.Вот что задействовано:
- Статические и Динамические роли.Статические роли не зависят от данных (например, я получаю роль разработчика в приложениях), в то время как динамические роли зависят от SecurityContext (например, финансовый сотрудник департамента получает роль «Финансовый сотрудник», когда она просматривает счета своего отдела).
- Разрешения, которые назначены статической или динамической ролям.
- SecurityContext, который инкапсулирует все данные, необходимые для проверки разрешения, которые должны быть выполнены, включая текущего пользователя и любые данные (например, номера счетов, идентификаторы документов предложений, даты транзакций, что угодно).
- SecurityContextValidator, который принимает SecurityContext и возвращает набор или роли, которые действительны для указанного пользователя в указанном SecurityContext.Таким образом, логика, которая определяет, кто может видеть, что находится в этом классе.
- Один SecurityContextValidator на SecurityContext.Это сопоставление регистрируется при инициализации с помощью SecurityContextManager.Я использую Ninject для загрузки моего модуля безопасности, который выполняет это при запуске.
- Контекст по умолчанию, используемый, если в разрешении не указан SecurityContext, который просто содержит основную информацию из безопасности Asp.Net.
- SecurityService, предоставивший пользователю, SecurityContext и разрешение, определяет все роли, которые пользователь имеет в этом SecurityContext, и проверяет, есть ли у какой-либо из ролей проверяемое разрешение.
При этомточка, вот пример потока в Asp.Net MVC:
- Получить HttpRequest
- Аутентификация с помощью проверки подлинности с помощью форм
- Путь к действию контроллера
- , если(Permission.GetByName ("CanDoSomething"). IsAllowed ()) {// продолжить
- [Inside Permission.IsAllowed] -
- SecurityService получает SecurityContext
- Найти SecurityContextValidator для указанного SecurityContext
- Объединить все статические и динамические роли из SecurityContextValidatили
- Перебирайте роли и проверяйте, есть ли у каждой из них запрашиваемое разрешение.
- Верните True или False!
Чтобы упростить задачу, я выбрал однусделайте следующий шаг и создайте AbstractContextProtectedAttribute, который ожидает делегата SecurityContextFactory, который может создать SecurityContext (например, с помощью HTTPRequest) и разрешение для проверки с указанным SecurityContext.Подклассы этого класса могут затем использоваться для украшения действий контроллера.
Фу!Итак, теперь все, что мне нужно, настроить таблицу пользователей, ролей, разрешений и сопоставить их друг с другом, определить все разрешения в базе данных.Я написал подключаемый SecurityPersistenceService, который делает инфраструктуру безопасности независимой от используемой стратегии персистентности - к сожалению, у нас есть все - от DataReaders, DataAdapters до Linq2Sql и EF.Но, по крайней мере, мы можем написать код, подобный этому:
[Protected("CanAccessX")] // Checks using default context
public class SomeController
{
[Protected("CanSeeY")] // Checks using default context
public PartialViewResult GetY(<parameters>)
{
var canSeeY_Variation1 = Permission.Get("CanSeeY_Variation1") ;
var y_Variation1_Context = new Y_Variation1_Context { <build your context here> } ;
if (canSeeY_Variation1.IsAllowed(y_variation1_Context))
{
<return variation 1 view>
}
// Y_Variation_2...etc
}
}
И чтобы это работало, при запуске я регистрирую соответствующие валидаторы:
public class MyNinjectModule
{
public override void Load()
{
// Wire up a persistence service for the security framework
// to use.
SecurityService.SecurityPersistenceService = new MySecurityPersistenceServiceImplementation() ;
// This is what allows the SecurityService to figure out what Validator to use
// in a specified Context to get the User's Roles.
SecurityService.RegisterValidator<Y_Variation1_Context>(new Y_Variation1_ContextValidator(...)) ;
}
}
Сейчас я работаю над дополнением к этой инфраструктуре, которое позволяет мне выполнять эти проверки над перечисляемыми данными, таким образом, добавляя все объекты моего домена в инфраструктуру безопасности. Единственный чистый способ сделать это - использовать АОП. Я работал на Java и использовал AspectJ. Сейчас я рассматриваю PostSharp.
Надеюсь, это даст вам возможность подумать о вашей проблеме.