Лучший способ реализовать детализированную авторизацию для веб-приложения?

StackOverflow https://stackoverflow.com/questions/279415

Вопрос

Я работаю над веб-приложением Rails, и в настоящее время им пользуются около 20 пользователей.

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

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

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

Я хочу изменить это двумя способами:

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

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

Как вы думаете, какой самый элегантный способ реализовать это?

Ответы, относящиеся к Rails, не нужны, я просто хочу знать, как это должно быть реализовано в приложении, управляемом данными.

Наконец, вот как это реализовано в настоящее время:

def authorized?
  current_user.role.foo? or current_user.role.bar?
end

И вот моя первоначальная идея, которая, я думаю, не самый лучший способ решить эту проблему:

+------------+------------+---------+
| department | controller | action  |
+------------+------------+---------+
| accounting | payments   | index   |
| accounting | payments   | new     |
| accounting | payments   | create  |
| accounting | payments   | edit    |
| accounting | payments   | update  |
| accounting | payments   | destroy |
| sales      | payments   | new     |
| sales      | payments   | create  |
| sales      | payments   | edit    |
| sales      | payments   | update  |
+------------+------------+---------+

или

+------------+----------+-------+--------+------+--------+--------+
| department | model    | list  | create | read | update | delete |
+------------+----------+-------+--------+------+--------+--------+
| accounting | payments | TRUE  | TRUE   | TRUE | TRUE   | TRUE   |
| sales      | payments | FALSE | TRUE   | TRUE | TRUE   | FALSE  |
+------------+----------+-------+--------+------+--------+--------+
Это было полезно?

Решение

Основная концепция авторизации, как я ее понимаю, - это роль.Роль может выражать различные вещи:

  1. отношение пользователя к системе в целом (например.быть администратором системы)
  2. отношение пользователя к какому-либо виду сущностей (например.быть модератором комментариев)
  3. отношение пользователя к какой-то конкретной сущности (например.быть владельцем какого-то ресурса)
  4. какое-то другое сложное отношение (например.быть другом пользователя, который является владельцем какого-либо ресурса)
  5. у этого пользователя есть какой-то атрибут (ы) или он отвечает на какое-то сообщение каким-то определенным образом (например.быть подростком)

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

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

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

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

Другие советы

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

описана аналогичная ситуация / решение здесь

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

Я думаю, причина, по которой раствор выглядит не очень СУХИМ, заключается в том, что он повторяется:

  1. В названиях отделов, и
  2. В отделе возможностей

Что касается # 1, то имело бы смысл создать таблицу departments и присвоить каждому отделу идентификатор.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top