нужно некоторое представление о том, как управлять ролями в моем приложении (ASP.NET MVC3)

Я разрабатываю сайт, который является своего рода онлайн-работе, там будут какие-то пользователи и некоторые постоянные Программирование проектов, и каждый пользователь может иметь несколько ролей, например, один конкретный пользователь может быть проект менеджер проекта и разработчик другого проекта. естественно, руководитель проекта имеет больше полномочий, чем разработчик в проекте. мой вопрос в том, как аккуратно управлять этим в моем коде? Я собирался использовать свой пользовательский поставщик ролей и использовать Авторизовать атрибут с этим, но этого недостаточно, так как мне нужен идентификатор проекта плюс идентификатор пользователя, чтобы найти роль пользователя в конкретном проекте.

7 ответов


сначала вам нужно будет создать дополнительные таблицы для расширенного управления ролями, такие как projects а там отношения с users в контексте operations, который может быть вашим controller's actions.

один из способов сделать это, чтобы создать свой собственный стол для roles. В этом случае вы будете использовать только asp net membership users, но все зависит от ваших требований.

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

это очень просто.

[CustomAuthorize]
//[Authorize]
public ActionResult GetProjectTasks(string projectname)
{

}

для этого Вам должен присущ ваш класс от FilterAttribute а также для реализации IAuthorizationFilter интерфейс.

 public void OnAuthorization(AuthorizationContext filterContext)
    {
        HttpCookie authCookie = filterContext.HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];

        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            var identity = new GenericIdentity(authTicket.Name, "Forms");
            var principal = new GenericPrincipal(identity, new string[] { authTicket.UserData });
            filterContext.HttpContext.User = principal;
        }

        var controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
        var action = filterContext.ActionDescriptor.ActionName;
        var user = filterContext.HttpContext.User;
        var ip = filterContext.HttpContext.Request.UserHostAddress;

        var isAccessAllowed = CustomAuthenticationLogic.IsAccessAllowed(controller, action, user, ip);
        if (!isAccessAllowed)
        {
            // Code if user is authenticated
            FormsAuthentication.RedirectToLoginPage();
        }            
    }

в методе OnAuthorization, вы можете получить всю информацию, которая может потребоваться в пользовательскую логику авторизации как HttpContext, Controller имя, Action имя. Вы должны просто вызвать свою пользовательскую логику аутентификации из этого метода. Пользовательская логика проверки подлинности может выглядеть следующим образом.

 public class CustomAuthenticationLogic
{
    public static bool IsAccessAllowed(string controller, string action, IPrincipal user, string ip)
    {
        //
        // Your custom logic here              
        //              
    }
} 

Я сделал некоторое исследование некоторое время назад и могу заверить вас:

  1. ASP.NET встроенные функции, скорее всего, не помогут (нет никакого способа принять во внимание такие вещи, как project Id)
  2. модель доступа на основе ролей наиболее подходит, существуют различные способы ее реализации. Азман, предложенный Rusted, на самом деле хорош, но управление правилами, связанными с контекстом, может быть сложным. Например: пользователь A выполняет операцию B в проекте C, в то время как его позволяет сказать воскресенье. Взгляните на Азман.
  3. смешивание правил доступа с кодом крайне плохо. Ваша модель безопасности не должна быть связана с тем, как работает приложение (ASP.NET MVC) так что это неправильно:
var isAllowed = AccessControl.IsAccessAllowed(controller, action, user, ip);

это должно выглядеть так:

var isAllowed = AccessControl.IsAccessAllowed(user, operation, context);

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

где операция "войти", "отправить ответ", "Читать темы" и т. д. контекст-это все остальное, как вы "идентификатор проекта", " день недели", "user ip", etc

есть много вещей, которые могут быть написаны, например, перекрытие ролей, контекст и т. д. Короче говоря: Google для "модели доступа на основе ролей .NET", вероятно, может быть проще написать небольшую пользовательскую структуру безопасности. Заставьте его работать с пользователями, ролями, операциями и идентификатором проекта

ролям назначаются операции, Роли назначаются пользователям с определенным идентификатором проекта, вы можете жестко кодировать операции и роли, поэтому в вашей БД будет только одно небольшое изменение: пользователь на роли отображение


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

таким образом, ваше представление будет очень тонким, оно будет отображать материал в зависимости от этих логических свойств ViewModel.

Итак, представляя, что ваш пользователь может только читать, вы можете иметь свойство bool IsReadOnly, которое будет заполняться в контроллер, в зависимости от правил авторизации, и который будет использоваться в представлении, например, для создания меток вместо текстовых полей.


Мне нравится основная идея: с Асман - это концепция программирования против операции.

операции очень гранулированные вещи, которые не должны иметь перекрытия в использовании и определяются только разработчиком. Группируя операции в задачи и задачи в роли, а затем сопоставляя участников (пользователей и группы) с ролями, вы получаете очень мощную модель для определения авторизации в приложении. Поскольку вы программируете непосредственно на операции, вашему коду не нужно какие роли у пользователя и которые могут быть изменены администратором во время выполнения. Фактически, кто-то может определить совершенно другой набор ролей для использования операций, которые вы используете в своем коде, и вам вообще не нужно будет менять код. Вот где настоящая сила.

Я не имею в виду" использовать AzMan в вашем приложении " (но, возможно, вам стоит попробовать). Это мощная модель, но она также сложна и, вероятно, чрезмерна для простых вещей. Если у вас есть роль или две и операции, которые они защищают, не перекрываются или вряд ли изменятся, тогда это вероятно, это не оправдано.


Я бы предложил вам создать пользовательский Authorize фильтр путем расширения встроенного


вы можете groups на основе roles.

затем добавьте разных пользователей в определенные группы. Группы могут быть >

1) Admin Group  
2) Developer Group  
3) Project1-QA Group  
4) Project2-Manager Group

сохранить отображение [user - group] и [group - projects] в зависимости от дизайна вашей базы данных.

вы можете иметь столько ролей(групп) для одного пользователя, как вы хотите.


очень простой подход-для управления доступом по всему сайту вы можете добавить столбец INT в таблицу пользователя и сопоставить каждый бит этого INT с [flags] перечисление - например,[Flags] enum Access { UpdateProjects, AddProjects }.

для управления доступом для каждого проекта создайте таблицу с именем, например, ProjectAccessControl с тремя столбцами: ProjectID (внешний ключ к таблице проекта), UserID (внешний ключ к таблице пользователя) и Role (INT). Столбец роли является INT, и каждый его бит должен означать другой логический флаг (как и в предыдущем примере, вы можете сопоставьте это с перечислением в C#) и скажите, что если первый бит включен, то у пользователя есть права на обновление описания, если второй бит включен, пользователь может изменить расписание и так далее.

[Flags]
enum ProjectAccessRole
{
    UpdateDescription,
    ChangeSchedule,
    etc...
}

в коде вы можете проверить, имеет ли роль пользователя право обновлять расписание таким образом:

if( (intUserRole & ProjectAccessRole.ChangeSchedule) 
     == ProjectAccessRole.ChangeSchedule)
{
    /*user has right*/
}

затем вы можете обернуть эту проверку в простую функцию, которая принимает два параметра: 1) роль, которая должна быть проверена, если она есть 2) роль. Тогда вы просто позвоните HasRights(intUserRole, ProjectAccessRole.ChangeSchedule);.