ASP.NET MVC3 Управление ролями и разрешениями -> С назначением разрешений во время выполнения - PullRequest
18 голосов
/ 02 сентября 2011

ASP.NET MVC позволяет пользователям возможность назначать разрешения для функциональности (например, Действия) в Время разработки примерно так.

[Authorize(Roles = "Administrator,ContentEditor")]
public ActionResult Foo()
{
    return View();
}

Для фактической проверки разрешения можно использоватьследующее утверждение в представлении (Razor):

@if (User.IsInRole("ContentEditor"))
{
    <div>This will be visible only to users in the ContentEditor role.</div>
}

Проблема с этим подходом состоит в том, что все разрешения должны быть установлены и назначены как атрибуты при время разработки .(Атрибуты скомпилированы с DLL, поэтому в настоящее время я не знаю ни одного механизма для применения атрибутов (для предоставления дополнительных разрешений), таких как [Authorize (Roles = "Administrator, ContentEditor")] при время выполнения .

В нашем случае использования клиент должен иметь возможность изменить какие пользователи имеют какие разрешения после развертывания .

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

Какие варианты стратегий доступны дляРазрешить определять разрешения для контроллеров / представлений / действий MVC вне атрибутов (как в базе данных), оценивать и применять во время выполнения?

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

Спасибозаранее за любые идеи или идеи.

Ответы [ 4 ]

21 голосов
/ 02 сентября 2011

Какие есть варианты стратегий, позволяющие определять разрешения для контроллеров / представлений / действий MVC вне атрибутов (как в базе данных), оценивать и применять во время выполнения?

Настраиваемый атрибут Authorize - это одна из возможностей достижения этого:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        Roles = ... go ahead and fetch those roles dynamically from wherever they are stored
        return base.AuthorizeCore(httpContext);
    }
}

, а затем:

[MyAuthorize]
public ActionResult Foo()
{
    return View();
}
16 голосов
/ 02 сентября 2011

Поскольку я ленивый, я не мог быть обеспокоен тем, что катал свой собственный атрибут, и использовал для этого FluentSecurity В дополнение к возможности применять правила во время выполнения, он позволяет настраивать способ проверки членства в ролях.В моем случае у меня есть настройка файла конфигурации для каждой роли, а затем я реализую что-то вроде следующего:

// Map application roles to configuration settings
private static readonly Dictionary<ApplicationRole, string> 
    RoleToConfigurationMapper = new Dictionary<ApplicationRole, string>
        {
            { ApplicationRole.ExceptionLogViewer, "ExceptionLogViewerGroups" }
        };

затем применяются роли приложений, как

SecurityConfigurator.Configure(
    configuration =>
    {
        configuration.GetAuthenticationStatusFrom(() =>
            HttpContext.Current.User.Identity.IsAuthenticated);
        configuration.GetRolesFrom(() => 
            GetApplicationRolesForPrincipal(HttpContext.Current.User));
        configuration.ForAllControllers().DenyAnonymousAccess();
        configuration.For<Areas.Administration.Controllers.LogViewerController>()
            .RequireRole(ApplicationRole.ExceptionLogViewer);
    });

filters.Add(new HandleSecurityAttribute());

, а затемпроверка выполняется

public static object[] GetApplicationRolesForPrincipal(IPrincipal principal)
{
    if (principal == null)
    {
        return new object[0];
    }

    List<object> roles = new List<object>();
    foreach (KeyValuePair<ApplicationRole, string> configurationMap in
             RoleToConfigurationMapper)
    {
        string mappedRoles = (string)Properties.Settings.Default[configurationMap.Value];

        if (string.IsNullOrEmpty(mappedRoles))
        {
            continue;
        }

        string[] individualRoles = mappedRoles.Split(',');
        foreach (string indvidualRole in individualRoles)
        {
            if (!roles.Contains(configurationMap.Key) && principal.IsInRole(indvidualRole))
            {
                roles.Add(configurationMap.Key);
                if (!roles.Contains(ApplicationRole.AnyAdministrationFunction))
                {
                    roles.Add(ApplicationRole.AnyAdministrationFunction);
                }
            }
        }
    }

    return roles.ToArray();
}

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

2 голосов
/ 27 августа 2012

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

http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/

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

http://www.lhotka.net/weblog/PermissionbasedAuthorizationVsRolebasedAuthorization.aspx

0 голосов
/ 02 сентября 2011

Если вам нужно выполнить авторизацию на основе метода или контроллера (запретить доступ ко всему методу или контроллеру), вы можете переопределить OnAuthorization в базе контроллера и выполнить собственную авторизацию.Затем вы можете построить таблицу, чтобы посмотреть, какие разрешения назначены этому контроллеру / методу, и перейти оттуда.

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

Другой вариантИспользуя ваш второй подход, вы должны сказать что-то вроде этого:

@if (User.IsInRole(Model.MethodRoles)) 
{ 
    <div>This will be visible only to users in the ContentEditor role.</div> 
} 

И затем в вашем контроллере заполните MethodRoles ролями, назначенными этому методу.

...