Вопрос

Допустим, у меня есть приложение ASP.Net MVC, и это приложение (пользовательский интерфейс) ссылается на уровень бизнес-логики (BLL), а BLL ссылается на мой уровень доступа к данным (DAL).

Я использую пользовательский поставщик членства и ролей для авторизации.

Я пытаюсь определить, какие слои должны ссылаться на моего поставщика членства.

В MVC вы можете выполнять проверку авторизации следующим образом:

[Authorize(Roles = "SomeRoleName")]
public ActionResult Index()
{
//do something
}

И в моем BLL я, возможно, захочу проверить, есть ли у Пользователя такая же роль:

public static bool IsRoleEditor(User user, Role userRole)
  {
   bool retValue = false;

   if (user.Application.AppID == UserRole.Application.AppID)
   {
        if (Roles.IsUserInRole("ModifyRoles"))
        {
           retValue = true;
        }


    return retValue;
   }

Если я сделаю это, мне пришлось бы ссылаться на классы членства и создавать их экземпляры на обоих уровнях.Правильно ли это спроектировать подобное приложение?Похоже на большую избыточность.

Поскольку у меня есть BLL, могу ли я избежать использования атрибутов "[Authorize(Roles = "SomeRoleName")]" и вместо этого вызвать функцию BLL из кода MVC, чтобы проверить, находится ли пользователь в роли?Если я сделаю это, MVC по-прежнему нуждается в ссылке на поставщика членства для аутентификации и тому подобное в любом случае, чтобы воспользоваться преимуществами входа в систему и других элементов управления ASP, верно?

Я сбился с пути и направляюсь не в том направлении?

Это было полезно?

Решение

На мой взгляд, это слабость членства / ролевого дизайна.

Чтобы обойти это, например, чтобы иметь основанную на ролях авторизацию как на уровне пользовательского интерфейса, так и на уровне BLL в распределенном n-уровневом приложении, можно было бы представить службу на уровне BLL, которая предоставляет соответствующие биты (GetRolesForUser и т. д.) и реализуется путем вызова RoleProvider на сервере.

Затем реализуйте пользовательский RoleProvider на клиенте, который реализуется путем вызова службы, предоставляемой BLL.

Таким образом, уровень пользовательского интерфейса и уровень BLL совместно используют один и тот же RoleProvider. Уровень пользовательского интерфейса может использовать знания о ролях текущего пользователя для улучшения пользовательского интерфейса (например, скрытие / отключение элементов управления пользовательского интерфейса, соответствующих неавторизованным функциям), а BLL может гарантировать, что пользователи не смогут выполнить бизнес-логика, для которой они не авторизованы.

Другие советы

Отличный вопрос, я задал себе то же самое сегодня. Одна из идей, которые у меня были (но я не совсем уверен, что это лучший способ), - это использовать интерфейс (например, IRoleProvider), который вы можете передать в свой BLL для проверки вашего доступа.

public static bool IsRoleEditor(User user, IRoleProvider rp)
{
     return (rp.IsUserInRole(user,"ModifyRoles"));
}

При этом вы по-прежнему проверяете свой доступ в своем BLL, вы можете использовать макет в своих модульных тестах для проверки своей логики, и вам просто нужно создать класс (или реализовать это в классе baseController) на вашем веб-сайте MVC который будет реализовывать IRoleProvider и выполнять соответствующую проверку с использованием API авторизации ASP.NET.

Надеюсь, это поможет.

Получите свой пользовательский объект для реализации IPrincipal интерфейса и распределите его по слоям.Тогда вы все равно можете использовать встроенный атрибут [Autorize].

Хотя написано более 3 лет назад и о касле, эта статья может помочь.Это начинает проникать в суть дела на полпути вниз.

HTHS
Чарльз

Почему бы не передать роли в ваш BLL, чтобы у вас не было никакой зависимости от членства?Или используйте интерфейс, как предложил MartinB.

Что произойдет в будущем, когда ваши заинтересованные лица решат перейти на другую форму аутентификации, а вы больше не будете работать с Роль возражать?

Пример:

IsRoleEditor(User user, string[] roles)
{
  return roles.Contains("ModifyRoles");
}

Вы не упускаете из виду суть MVC?MVC естественным образом разбивается на уровни.Модель (DAL), контроллер (BLL), Вид (Презентация).Они могут использоваться в разных проектах, если хотите, но поскольку контроллер имеет всю бизнес-логику - вам нужно только получить доступ к RoleProvider там.

Затем примените шаблоны, такие как репозиторий, шаблон и т.д., чтобы разделить их еще больше, если хотите.

Дэви

Вызывать контроллер MVC как «пользовательский интерфейс» - это совсем не то, что нужно. «C» в MVC - это часть вашего BLL, даже если он ссылается на классы, которые вас Назову БЛЛ. Тем не менее, это не точка вашего вопроса.

Я думаю, что решил бы эту проблему, задав вопрос: "Есть ли реальное требование для 100% разделения вашего приложения" UI "и вашего BLL"? ". Если оба компонента имеют общую зависимость от поставщиков участников / ролей, пусть так и будет.

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

Я думаю, что ответ Джо выше имеет большой смысл, хотя ...

Я думаю, что ты делаешь хорошо.

Авторизация и аутентификация должны находиться на уровне сервисов, который, возможно, передается вашим контроллерам.

Если контроллер устанавливает Принципал и Идентичность, а затем вы используете их в контроллере с помощью атрибутов MVC, то это звучит как хорошая идея.

Было бы неплохо спрятать вашего провайдера членства MVC за интерфейсом, чтобы вы могли поменять его на провайдера членства WinForms (например) и могли бы тестировать свои контроллеры по отдельности.

Роль доступа обычно не должна быть в списке BLL. Доступ является обязанностью пользовательского интерфейса.

С учетом вышесказанного используйте интерфейс IPrinciple, как указано выше. У вас есть доступ к IPrinciple на уровне потоков.

Thread.CurrentPrincipal
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top