Merge branch 'master' of github.com:warpc/rosa-build

This commit is contained in:
Ilya Krasilnikov 2011-10-25 04:15:01 +04:00
commit 733a34f0f8
2 changed files with 161 additions and 25 deletions

View File

@ -5,7 +5,14 @@
--------------
ACL предназначена для контроля прав пользователя на выполнение действий в
системе доступа к моделям по областям видимости.
системе и доступа к моделям по областям видимости.
Решаемые задачи
---------------
* Проверка наличия у пользователя прав для выполнения метода контроллера;
* Прозрачная фильтрация моделей для исключения невидимых для пользователя
записей.
Возможности
-----------
@ -20,15 +27,55 @@ ACL предназначена для контроля прав пользова
* Объединение прав `acter`-ов на глубину одной модели (см. далее);
* Разграничение назначения ролей по классам (не завершено, на данный
момент не критично);
* Разграничение ролей на глобальные и локальные (см. далее);
* Разграничение ролей на глобальные и локальные (см. далее).
Типы моделей
------------
Типы моделей, с которыми взаимодействует ACL
--------------------------------------------
* __ActerModel__ -- модель, которая может выполнять действия, разрешенные
ролями, над другими моделями;
* __TargetTarget__ -- модель, над которой могут выполняться действия,
разрешенные ролями.
__ActerModel__ может иметь глобальную роль, которая определяет возможность
выполнения действий без привязки к конкретному экземпляру __TargetModel__ и
неограниченное количество прав по отношению к конкретному экземпляру
__TargetModel__.
__TODO__: *Реализовать дополнение необходимым функционалом моделей, выбранных
в качестве __ActerModel__ или __TargetModel__ при декларировании их роли в
системе*
Схема взаимодействия объектов ACL
---------------------------------
Функционал ACL реализуется путем взаимодействия моделей `Right, Role, Relation`,
реализующих основной функционал и особых моделей проекта, обозначенных на схеме
как `ActerModel` и `TargetModel`.
Экземпляры __ActerModel__ и __TargetModel__ связываются посредством модели
`Relation`, через которую экземпляр __ActerModel__ получает неограниченное
количество ролей по отношению к экземпляру __TargetModel__.
### Схема связей моделей:
--------------
| ActerModel |
/ --------------
--------- -------- |
| Right | | Role | V
--------- -------- ------------
... <= ... <= | Relation |
--------- -------- ------------
| Right | | Role | |
--------- -------- V
---------------
| TargetModel |
---------------
* Обозначения: <= -- Связь с несколькими моделями
<-,/,| -- Связь с одной моделью
* __Acter__ - модель, которая может выполнять действия, разрешенные ролями,
над другими моделями;
* __Target__ - модель, над которой могут выполняться действия, разрешенные
ролями;
Генератор прав
--------------
@ -50,12 +97,12 @@ ACL предназначена для контроля прав пользова
* Добавить к таблице моделей поле `visibility:text`;
* Добавить `attr_accessible :visibility` в модель;
* Создать `scope :by_visibility`, принимающий аргументом массив областей
видимости;
видимости.
После выполнения этих действий на странице редактирования роли появится поле
выбора областей видимости для этой модели.
Пример:
### Пример:
model VisibilitiesExample < ActiveRecord::Base
VISIBILITIES = ['open', 'hidden', 'open_for_admins']
@ -64,6 +111,8 @@ ACL предназначена для контроля прав пользова
scope :by_visibility, lambda {|v| {:conditions => ['visibility in (?)', v]}}
end
*Назначение методов описано в API*
Задание типа модели
-------------------
*Этот функционал скорее всего будет изменяться*
@ -82,7 +131,7 @@ ACL предназначена для контроля прав пользова
которой аргументом присвоить имя/имена связей с моделями, из которых должны
браться роли.
Примеры:
### Примеры:
* Модель, являющаяся __acter__:
@ -121,6 +170,78 @@ ACL предназначена для контроля прав пользова
has_many :objects, :as => :target, :class_name => 'Relation'
end
*Назначение методов описано в API*
Использование ACL в контроллере
-------------------------------
Если необходимо ограничить доступ ко всем методам контроллера по глобальной
роли пользователя вне зависимости от текущей модели, необходимо установить
`before_filter :check_global_rights`.
В случае, если у пользователя нет прав для выполнения текущего действия, он
будет переотправлен на предыдущую страницу.
Если необходимо проверить, может ли пользователь выполнить конкретное действие,
необходимо в начале этого метода вызвать метод `can_perform?`. Если методу
передан параметр, являющийся экземпляром класса __TargetModel__, метод возвратит
`true`, если одна или несколько ролей пользователя над этой моделью позволяет
ему выполнить может выполнить действие и `false` в противном случае. Если
необязательный параметр опущен, или в качестве параметра передано `:system`,
учитываются только глобальные роли.
### Примеры
* Контроллер, некоторые методы которого доступны для всех:
class StuffController < ApplicationController
def index # доступ у всех
...
end
def show # 'Что-то полезное' выполнится только у тех, чьи роли над
# @data позволяют выполнить конкретное действие.
@data = Stuff.find(params[:id])
if can_perform? @data
#что-то полезное
else
# сообщаем пользователю, что он не может выполнить действие
end
end
def create # 'Что-то полезное' выполнится только у тех, чьи
# глобальные роли позволяют выполнить метод
if can_perform?
# что-то полезное
else
# сообщаем пользователю, что он не может выполнить действие
end
end
end
* Контроллер, доступ к методам которого возможен только при наличии необходимых
прав в глобальных ролях:
class StuffController < ApplicationController
before_filter :check_global_rights # разрешаем доступ только тем,
# чьи роли это позволяют.
def index # доступ только у тех, кому это позволяет глобальная роль
...
end
def show # 'Что-то полезное' выполнится только у тех, чьи роли
# над @data это позволяют
@data = Stuff.find(params[:id])
if can_perform? @data
#что-то полезное
else
# сообщаем пользователю, что он не может выполнить действие
end
end
end
API для работы с ACL
--------------------
*Этот функционал скорее всего будет изменяться*
@ -130,23 +251,38 @@ API для работы с ACL
*  Методы классов:
- `relationable` -- устанавливает, кем является модель (acter/target)
- `relationable?` -- может ли иметь связь с ролью/ролями с другими
- `relation_acters` -- список моделей, которые могут иметь роли по отношению к другим (след. метод)
- `relation_targets` -- список моделей, над которыми могут совершаться действия
- `relation_acter? (model)`, `relation_target? (model)` -- является ли тем или другим
  - `inherit_rights_from (:relation_name | [:relation_names])` -- права из каких связанных моделей наследовать
  - `visible_to (model)` -- все видимые для модели записи, может включаться в цепочку (например, для paginate)
- `relation_acters` -- список моделей, которые могут иметь роли
по отношению к другим (след. метод)
- `relation_targets` -- список моделей, над которыми могут совершаться
действия
- `relation_acter? (model)`, `relation_target? (model)` -- является ли
тем или другим
  - `inherit_rights_from (:relation_name | [:relation_names])` -- права из
каких связанных моделей наследовать
  - `visible_to (model)` -- все видимые для модели записи, может
включаться в цепочку (например, для paginate)
* Методы инстансов:
- `add_role_to(acter, role)` -- привязать acter-а с ролью к текущей записи
- `add_role_on(target, role)` -- привязать текущую модель с ролью
- `roles_to(object)` -- если object == :system, возвращает глобальные роли текущей записи, если передана запись -- то роли текущей модели над записью
- `rights_to(object)` -- аргументы те же, но возвращается список прав, собранный из всех ролей
- `right_to(controller_name, action)` -- возвращает запись с правом на выполнение действия action в контроллере c именем controller_name
- `can_perform? (controller_name, action, target = :system)` -- показывает, может ли текущая модель выполнить действие контроллера над целью
- `roles_to(object)` -- если object == :system, возвращает глобальные роли
текущей записи, если передана запись -- то роли текущей модели над записью
- `rights_to(object)` -- аргументы те же, но возвращается список прав,
собранный из всех ролей
- `right_to(controller_name, action)` -- возвращает запись с правом на
выполнение действия action в контроллере c именем `controller_name`
- `can_perform? (controller_name, action, target = :system)` -- показывает,
может ли текущая модель выполнить действие контроллера над целью
### Методы потомков `ActiveController::Base`
- `can_perform? (target = :system)` -- может ли current_user выполнить текущее действие
- `check_global_rights` -- делает редирект назад, если пользователь вообще не может совершить текущее действие
- `roles_to(object)` -- возвращает список ролей current_user-а по отношению к объекту
- `rights_to(object)` -- возвращает список прав current_user-а по отношению к объекту
*Возможно, будут вынесены в хелпер для универсализации системы*
- `can_perform? (target = :system)` -- может ли `current_user` выполнить
текущее действие
- `check_global_rights` -- делает редирект назад, если пользователь вообще
не может совершить текущее действие
- `roles_to(object)` -- возвращает список ролей `current_user`-а по отношению
к объекту
- `rights_to(object)` -- возвращает список прав `current_user`-а по отношению
к объекту

View File

@ -1,4 +1,4 @@
class ApplicationController::Base
class ActionController::Base
def can_perform? target = :system
c = self.controller_name