Представления на основе ролей Django?

Я ищу информацию о том, как другие будут это строить. Я собираюсь предоставить представления на основе класса (группы django).

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

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

Это было сделано через какое-то стороннее приложение? А как бы вы подошли к этой проблеме?

Спасибо, Пит.


person slypete    schedule 10.10.2009    source источник
comment
Ребята, система разрешений django мне не подходит. Вот почему я прошу помощи в архитектуре: P   -  person slypete    schedule 10.10.2009


Ответы (9)


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

http://docs.djangoproject.com/en/dev/topics/auth/

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

Есть две части, на которые вам нужно обратить внимание.

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

Для 1. вы можете проверить разрешения в декораторе как таковом:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote')
def some_view(request):

Для 2. разрешения текущего пользователя, вошедшего в систему, хранятся в переменной шаблона {{ perms }}. Этот код проверяет то же разрешение, что и выше.

{% if perms.polls.can_vote %}
    <a href="/vote">vote</a>
{% endif %}

Чтобы сгенерировать список ссылок, вы можете перебрать user.get_all_permissions() и получить ссылки (или функцию, которая генерирует ссылку) из dict:

def more_elaborate_list_of_links_for_a_perm(user):
    return ["/link1", ...]

_LINKS = {
    'polls.can_vote' : lambda u: ["/user/specific/link/" + u.id],
    'polls.can_close': lambda u: ['/static/link/1', 'static/link/2'],
    'polls.can_open' : more_elaborate_list_of_links_for_a_perm
}

def gen_links(user):
    # get_all_permissions also gets permissions for users groups
    perms = user.get_all_permissions()
    return sum((_LINKS[p](user) for p in perms if p in _LINKS), [])

Вероятно, есть много других подходов.

person mbarkhau    schedule 10.10.2009
comment
Как бы вы сгенерировали список ссылок, чтобы предоставить пользователю встроенную систему разрешений django? - person slypete; 10.10.2009
comment
Для справки, я не выбрал этот ответ как лучший. Я так не думаю. - person slypete; 03.11.2009

У нас была аналогичная проблема. Группы Django НЕ ДЕЙСТВИТЕЛЬНО подходят для этого, но вы можете их впихнуть.

Мы сделали это следующим образом:

Каждый объект с контролируемым доступом имеет отношение ManyToMany к таблице групп. Каждая группа использовалась для определения определенного типа разрешения («может просматривать основные сведения о пациенте», «может редактировать контактную информацию пациента» и т. д.). Пользователи добавляются в группы, для которых у них должны быть разрешения (в вашем примере, когда вы видите только пациентов в этой больнице, у вас может быть группа «больница с видом на долину»).

Затем, когда вы переходите к отображению списка записей пользователю, вы фильтруете на основе соединения двух групп. Пользователь должен иметь все связанные групповые разрешения для просмотра данного объекта.

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

Что касается вашей проблемы с панелью ссылок, вы можете генерировать их программно, используя ту же систему - фильтровать на основе классов объектов, которые пользователь может видеть или редактировать, а затем использовать функцию типа get_absolute_url() (возможно, назовите ее get_index_url()), чтобы вернуть ссылки для индекса каждого класса объекта.

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

person Paul McMillan    schedule 29.10.2009
comment
В итоге я пошел по этому пути с нашим приложением, но это не идеально. Я обнаружил, что производительность немного упала. Я ищу лучшее решение ACL в другом месте - person Gevious; 27.02.2013
comment
Это вообще не масштабируется. Любые идеи по ACL? - person user710907; 29.05.2015

Есть новый очень интересный проект о разрешениях на основе ролей в Django: http://bitbucket.org/nabucosound/django-rbac

person jujule    schedule 02.11.2009

У меня не так давно была аналогичная проблема. Наше решение сработало, хотя оно может быть слишком простым для вашей ситуации. Как и все предполагают, мы использовали систему разрешений django, чтобы контролировать взаимодействие пользователей с моделями. Однако мы не просто попытались сгруппировать пользователей, мы также сгруппировали объекты с помощью GenericForeignKey.

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

class Group( models.Model ):
    name = models.CharField( ... )
    parent = models.ForeignKey( 'self', blank=True, null=True)
    content_type = models.ForeignKey( ContentType )
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey( 'content_type', 'object_id' )
    ...

Чтобы заставить его работать, мы также создали модель, которая будет служить профилем пользователя модели django User. Все, что он содержал, — это ManyToManyField, связанный с моделью Group выше. Это позволило нам предоставить пользователям доступ к нулю или большему количеству групп по мере необходимости. (документация)

class UserProfile( models.Model ):
    user = models.ForeignKey( User, unique=True )
    groups = models.ManyToManyField( Group )
    ...

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

person Thomas    schedule 30.10.2009

Если вам не нужны настоящие ACL для каждого объекта, вы можете просто использовать систему разрешений Django. Чтобы получить список всех доступных разрешений:

from django.contrib.auth.models import Permission
perms = Permission.objects.all()

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

Вы можете взломать эту систему Django, чтобы она соответствовала вашим потребностям с точки зрения этой модели авторизации (RBAC), или вы можете придумать решение, подобное ACL.

person Andrey Vlasovskikh    schedule 10.10.2009
comment
любой намек на acl для каждого объекта? - person gpilotino; 02.11.2009

На сайте для эксперта по вину Пино Нуар мы создали пообъектный доступ на основе ряда различных критериев. Если во входящей ссылке было поле реферера, совпадающее с доменным именем известной винодельни, то пользователь получал «токен винодельни», который распространялся на все статьи, дегустационные заметки и т. д., связанные с этой винодельней. Мы используем «именные жетоны» для раздачи на дегустациях, и они давали доступ к определенным частям сайта. Мы даже используем это, чтобы предоставить определенные типы разрешений поисковым роботам, а затем удостовериться, что ссылки, исходящие от этих поисковых систем, имеют те же разрешения, что и поисковые роботы (т. е. никаких маскирующих игр).

Короткая версия заключается в том, что вы можете создать класс (мы назвали их TokenBuckets, которые содержат токены), и каждый объект (на странице сведений, странице списка или что-то еще) может запрашивать TokenBucket пользователя, разрешен ли определенный уровень доступа.

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

person Peter Rowell    schedule 30.10.2009

Вы можете использовать роли пользователей django

https://github.com/dabapps/django-user-roles

person ecabuk    schedule 07.09.2012

Этот вопрос был задан в октябре 2009 г., но проблема все еще существует в июле 2012 г..

Я искал хорошее ролевое приложение и нашел django-permission. как лучший результат.

Мне нужны были три важные функции: Роли, вид Декораторы и Тег шаблона; очевидно, у django-permissions есть все. Прочтите его документы для его использования.

Единственным недостатком является то, что он находится в стадии разработки.

person Soask    schedule 04.07.2012

Мы использовали ролевую систему для решения аналогичной задачи. В основном пользователи имеют разрешения на выполнение различных ролей.

Функции представления были украшены:

def needs_capability(capability,redirect_to="/cms/"):
   def view_func_wrapper(view_func):
       def wrapped_view_func(request,*args,**kwargs):
           if not request.role._can(capability):
              return HttpResponseRedirect(redirect_to)
           return view_func(request,*args,**kwargs)
       return wrapped_view_func
   return view_func_wrapper

Остальная магия находится внутри атрибута request.role, который устанавливается внутри процессора контекста. Аутентифицированные пользователи получили Роль, для немытых масс — Роль-пустышку.

Доступ к информации был дополнительно ограничен внутри шаблонов:

 {% if not request.role.can.view_all_products %}
          Lots of products, yeah!
 {% endif %}

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

person phoku    schedule 02.11.2009