Авторизация в социальной сети - PullRequest
11 голосов
/ 13 июня 2011

Мне необходимо выполнить следующие действия, связанные с привилегиями:

У меня есть 3 пользователя:

- User A
- User B
- User C

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

- User A
    - Document A1, only allow contacts to view
    - Document A2, allow everyone to view
    - Document A3, allow no one to view except myself
    - Document A4, allow contacts, and contacts of contacts to view
- User B
    - Documents B1, B2, B3, B4 with similar privileges
- User C
    - Documents C1, C2, C3, C4 with similar privileges

User A имеет User B в качестве контакта, но не является контактом User C (User B и User C являются контактами).

Таким образом, User A сможетдля просмотра следующего:

- Document B1 (contacts can view)
- Document B2 (everyone can view) 
- Document B4 (contacts of contacts)
- Document C2 (everyone can view)
- Document C4 (contacts of contacts)

Может кто-нибудь объяснить, как будут обрабатываться эти привилегии.И если бы вы могли связать меня с любой документацией или статьями, которые помогли бы мне взяться за дело.Спасибо.

Ответы [ 5 ]

7 голосов
/ 13 июня 2011

К сожалению, система авторизации Django не позволяет назначать разрешения для объекта, только для класса.Здесь я предполагаю, что каждый ваш «Документ» является экземпляром класса модели.

Однако существуют многократно используемые приложения, которые значительно упрощают эту задачу.Взгляните на django-guardian или другие пакеты , которые работают на уровне объекта (или строки).

5 голосов
/ 22 июня 2011

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

Есть хорошая статья с некоторыми SQL-запросами, которая охватывает эту тему на http://techportal.inviqa.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/. Вместо того, чтобы пытаться обобщить всю статью, вот как концептуализировать проблему:

  • Начните с чистого листа бумаги.
  • Нарисуйте точку где-нибудь на странице для каждого человека (в данном случае, пользователей A, B и C). В терминах CS это «узел».
  • Нарисуйте стрелку от пользователя ко всем его контактам. В терминах CS это «направленный край» или «дуга».
    • Это не совсем ясно в вопросе, но похоже, что пользователь C должен быть контактом пользователя B или контактом с другими контактами пользователя A (поскольку пользователь A может читать C2 и C4).
    • Таким образом, в этом случае вы будете использовать пользователя A -> пользователя B и пользователя B -> пользователя C.

Кроме того, если «контакт» является взаимным, вы можете нарисовать отрезок линии (или двунаправленную стрелку) вместо стрелки. В терминах CS это будет «неориентированный» или «направленный» граф. Отношения в Facebook - это неориентированные отношения; если кто-то мой друг, то я тоже их друг. Напротив, если кто-то есть в моей адресной книге Outlook, я не обязательно в их. Так что это целенаправленные отношения.

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

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

Для общего случая в статье описаны некоторые SQL-запросы, которые могут дать некоторое представление. Но для вашей конкретной цели я бы хотел использовать несколько соединений.

Давайте рассмотрим таблицу Users с первичным ключом id вместе с другими его полями и таблицу HasContact, которая имеет только два столбца: userId и contactId. Предположим, что у пользователя A есть идентификатор 1, у пользователя B - 2, а у пользователя C - 3. HasContact имеет строки (1, 2) и (2, 3) для представления взаимосвязей, описанных выше.

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

Следующий запрос вернет все идентификаторы контактов пользователя:

SELECT contact.id
  FROM Users "user"
    LEFT JOIN Relationships "rel"
      ON user.id = rel.userid
    LEFT JOIN Users "contact"
      ON rel.contactId = contact.id
  WHERE user.id = $id_of_current_user

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

SELECT count(*)
  FROM Relationships "rel"
  WHERE rel.userid = $document_owner_user_id
    AND rel.contactid = $id_of_current_user

Если запрос возвращает 0, то мы знаем, что текущий пользователь , а не один из контактов владельца документа.

Мы можем обновить этот второй запрос, чтобы указать, является ли пользователь контактом:

SELECT count(*)
  FROM Relationships "rel_1"
    INNER JOIN Relationships "rel_2"
      ON rel_1.contactId = rel_2.userId
  WHERE rel_1.userid = $document_owner_user_id
    AND rel_2.contactid = $id_of_current_user

Это должно возвращать ненулевое значение, если в таблице «Отношения» есть записи, такие что ($document_owner_user_id, X) и (X, $id_of_current_user) существуют. В противном случае он вернет ноль.

Я знаю, что это длинный и несколько косвенный ответ, поэтому, пожалуйста, прокомментируйте, если у вас есть какие-либо вопросы.

3 голосов
/ 22 июня 2011

Вам нужен список контроля доступа (ACL) , который будет меняться в зависимости от сети каждого пользователя. ACL, а также разрешения на основе объектов недоступны в стандартном модуле django.contrib.auth. Я фактически реализовал ACL в Django, но он основан на классах, а не на объектах. В контексте вашего приложения оно будет работать так, как если бы User A мог просматривать любые документы, пока он находится в определенной авторизованной группе (скажем, Admins группа). Но его можно заставить работать так же, как User A просматривать документы User B s Если User A входит в группу Contacts для User B.

Я могу объяснить, как это сделать с точки зрения структуры модели для настроенного приложения аутентификации. Модели User и Permission будут такими же, как стандартное приложение аутентификации Django (вы можете скопировать их из models.py ). Затем вам нужна модель для представления разных уровней разрешений (Все, ContactsOfContact, Contact, Myself). Сделать это просто, как добавить другое поле в стандартную модель групп аутентификации django. Это поле будет внешним ключом той же модели, которая будет представлять группу, от которой будет наследоваться каждая группа. Теперь модель выглядит так:

class SocialGroup(models.Model):
  name = models.CharField(unique=True, max_length=150)
  parent = models.ForeignKey('self')

Теперь вы можете добавить отношения, например, Contacts group может просматривать все, что может просматривать Everyone group, установив Everyone group в качестве родителя для Contacts group. Обратите внимание, что с моделью Permission отношения внешних ключей отсутствуют. Далее нам нужен способ указать отношения между пользователями и группами.

class Relationship(models.Model):
  user  = models.ForeignKey(User)
  related_user = models.ForeignKey(User)
  related_by = models.ForeignKey(SocialGroup)

С этой моделью мы можем сказать, что User A (related_user) связан с User B (пользователь), находясь в группе User B s Contacts (related_by). Затем нам нужен способ указать разрешение для каждого документа.

class DocumentPermissions(models.Model):
  document = models.ForeignKey(Document)
  group = models.ForeignKey(SocialGroup)
  Permission = models.ForeignKey(Permission)

Теперь мы можем сказать, что Contacts группа имеет can_view разрешение на Document B1. Обратите внимание, что эта модель должна идти туда, где находится модель Document, а НЕ в auth models.py в нашем новом приложении auth. Вот и все, теперь все, что нам нужно сделать, это написать логику, чтобы найти разрешения для данного пользователя для данного документа. Итак, вот что нам нужно сделать, когда User B пытается просмотреть Document A1,

  • Сначала проверьте, к какому лицу относится документ (User A)
  • Затем найдите группу отношений между владельцем и тем, кто пытается получить доступ к документу, из модели отношений (Контакты).
  • Затем проверьте DocumentPermissions, чтобы увидеть, имеет ли эта группа или любая группа, от которой она наследует, разрешения на просмотр документа.

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

3 голосов
/ 13 июня 2011

В основном вам нужно Ограничить доступ вошедшим в систему пользователям, прошедшим тест . Но часть с «контактами контактов» может привести к очень сложным sql-запросам. И я предлагаю вам переосмыслить это требование. (У меня много хороших друзей, которым я люблю и которым доверяю. Но у них в друзьях много разных странных людей ...)

0 голосов
/ 19 июня 2011

Вы можете включить поле «друзья друзей». Это будет очень большой стол (скажем, 200 * 200 * N = 40000 * N ... или очень большой, если у вас нет ограничений на друзей, а кто-то дружит с миллионом людей - это 1 миллион человек с 1 миллионом FoF). ) но это было бы проще, чем попасть в базу данных 200 раз за просмотр.

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