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

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

7 ответов

Решение

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

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

Во-вторых, вы должны справиться с этим в MVCНа мой взгляд, лучший способ это реализовать через свой собственный Authorization атрибут, и украсить действия вашего контроллера с вашим пользовательским атрибутом авторизации вместо [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, скорее всего, не помогут (нет способа учесть такие вещи, как идентификатор проекта)
  2. Ролевая модель доступа является наиболее подходящей, есть разные способы ее реализации. AzMan, предложенный Rusted, на самом деле хорош, но управлять правилами, связанными с контекстом, может быть сложно. Например: пользователь A выполняет операцию B в проекте C, в то время как его, скажем, воскресенье. Посмотрите на Азмана.
  3. Смешивать ваши правила доступа с кодом очень плохо. Ваша модель безопасности не должна быть связана с тем, как работает приложение (ASP.NET MVC), так что это неверно:
var isAllowed = AccessControl.IsAccessAllowed(controller, action, user, ip);

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

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

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

где операция "Вход в систему", "Ответ на сообщение", "Чтение тем" и т. д. контекст всегда важен, например, "идентификатор проекта", "день недели", "ip пользователя" и т. д.

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

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

Вы можете иметь groups основанный на roles,

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

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

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

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

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

Вы должны переопределить AuthorizeCore метод и там у вас есть вся ваша логика проверки роли. user id Вы должны хранить в сессии и project id Вы должны понять это.

public override bool AuthorizeCore(HttpContextBase httpContext)
{

}

AuthorizeAttribute исходный код - http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/913d37658a44

Пример пользовательского атрибута авторизации: http://msdn.microsoft.com/en-us/library/ee707357(v=vs.91).aspx

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

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

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

Мне нравится основная идея AzMan - концепция программирования против операций.

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

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

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

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

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

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

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

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

Другие вопросы по тегам