Подтвердить что ты не робот

Ролевые на основе Django?

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

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

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

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

Спасибо, Пит

4b9b3361

Ответ 1

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

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

Как правило, в вашем коде вы проверяете, имеет ли пользователь разрешение. У пользователя есть свои права и права тех групп, к которым он принадлежит. Это можно легко администрировать из консоли администратора.

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

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

Для 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), [])

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

Ответ 3

У нас была аналогичная проблема. Группы Django не подходят для этого, но вы можете включить их.

То, как мы это делали, было следующим:

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

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

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

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

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

Ответ 4

У меня была аналогичная проблема не так давно. Наше решение сделало трюк, хотя это может быть слишком просто для вашей ситуации. Как и каждый, мы использовали систему разрешения 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. Все, что содержалось в нем, - это ManyToManyField, связанный с моделью Группы выше. Это позволило нам предоставить пользователям доступ к нулевым или более группам по мере необходимости. (документация)

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

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

Ответ 5

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

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

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

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

Ответ 6

На сайте для специалиста по вину Pinot Noir мы создали доступ к каждому объекту по нескольким различным критериям. Если входящая ссылка имела поле референта, которое соответствовало доменному имени признанного винного завода, тогда пользователь получил "токен винзавода", который был расширен для всех статей, дегустационных заметок и т.д., Связанных с этим винзаводом. Мы используем "named tokens" для получения путевок при дегустационных мероприятиях, и они дали доступ к определенным частям сайта. Мы даже используем это, чтобы предоставить определенные типы разрешений поисковым роботам, а затем убедитесь, что ссылки, которые поступают из этих поисковых машин, имеют те же права, что и паук (т.е. Без клоакинга).

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

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

Ответ 7

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

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

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

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

Ответ 9

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

Просмотр полученных функций:

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, который получил установленный внутри контекстного процессора. Аутентифицированные пользователи получили роль, для немытых масс DummyRole.

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

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

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