2015-08-18 3 views
5

Я разрабатываю авторизацию приложения DRF. Мне нужно использовать роли, а не только разрешения.Проектирование авторизации на основе ролей Django Rest Framework

У меня есть модель (например, project), в которой у меня есть некоторая информация (например, имя, описание), которые могут быть изменены некоторыми ролями (например, admin). Но в то же время существуют и другие роли (например, worker), которые не могут изменять эту информацию внутри этой модели, но могут изменять некоторые другие данные (например, начальную и конечную даты).

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

С другой стороны, я думал, что могу разделить модель на две разные модели. Один из них содержит данные, которые могут изменять только одна роль (admin), а другая - другие данные, которые могут быть изменены обоими ролями (admin, worker). Таким образом, мне не придется анализировать HTTP-запрос, потому что, если я получаю запрос POST/PUT, влияющий на первую модель, и у пользователя есть рабочая роль, я могу прямо ее отклонить.

Эта ситуация случается с более чем одной моделью.

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

Дополнительные примечания (обратная связь будет очень ценится):

  • я, скорее всего, будет использовать django-role-permissions модуль для выполнения ролей и разрешений. Я не могу использовать встроенные группы django, потому что, хотя вы можете добавлять к ним разрешения, я буду использовать их для группировки пользователей (не имея ничего общего с ролями).

  • Я создам связь между ролями и разрешениями (разрешение на основе строк, такое как , modify_project_description) в файле разрешений.

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

ответ

1

Немного подумав, я нашел два решения.

Первое решение было (вместо того, чтобы делить модели, как я упоминал в вопросе), объявляя разные конечные точки (URL) для каждого типа действия, которое должно произойти. Затем в каждой конечной точке serializer определяют действительные параметры через переменную класса fields.

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

Это решение имеет много проблем и не совсем RESTful. Вы можете получить десятки разных URL-адресов. В моем случае, учитывая, что API невелик, и действия были ограничены, что, возможно, не было проблемой в краткосрочной перспективе, но, несомненно, это было бы проблемой при изменении требований приложения.

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

Я бы предложил использовать словари в качестве используемой структуры данных для таблицы разрешений, чтобы каждая проверка разрешений была O(1).

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

Я применил проверку разрешений, переопределив метод check_permissions() в классе ModelSetView. Будьте внимательны и сохраняйте оригинальную функциональность check_permissions().

2

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

Другим вариантом может быть использование пользовательского класса сериализатора, который применяет readonly к некоторым полям. get_serializer на подклассе ViewSet может быть хорошим местом для создания точки, вы должны найти текущего пользователя в self.request.user.

+1

Вы заслуживаете повышения, потому что я в конечном итоге реализую все, что вы упоминаете (кроме прокси-модели). – newlog

Смежные вопросы