Пирамидальная авторизация хранимых предметов
Я пытаюсь создать политику авторизации, которая учитывает владение "элементом". Например, некоторые пользователи X "владеют" элементами A, B, C. Они доступны через URL-адреса, такие как /item/{item}/some_options
.
Как я могу получить информацию о {item}
к объекту политики авторизации (вызову permits ())? Помещает дополнительную информацию в контекст хорошей идеи (я делаю только маршрутизацию на основе маршрутов). Как мне это сделать?
1 ответов
вы можете сделать это с помощью ACLAuthorizationPolicy
в сочетании с отправкой URL с помощью пользовательского дерева ресурсов, предназначенного для этой цели.
например, у вас есть разрешения для Foo
объекты и разрешения для Bar
объекты. Эти ACL можно найти путем обхода дерева ресурсов с помощью URL-адресов:
/foos/{obj}
/bars/{obj}
ваше дерево ресурсов затем становится иерархией разрешений, где в любой точке дерева вы можете разместить __acl__
на ресурсе объект:
root (Root)
|- foos (FooContainer)
| `- {obj} (Foo)
`- bars (BarContainer)
`- {obj} (Bar)
эту иерархию можно представить в дереве ресурсов:
class Root(dict):
# this is the root factory, you can set an __acl__ here for all resources
__acl__ = [
(Allow, 'admin', ALL_PERMISSIONS),
]
def __init__(self, request):
self.request = request
self['foos'] = FooContainer(self, 'foos')
self['bars'] = BarContainer(self, 'bars')
class FooContainer(object):
# set ACL here for *all* objects of type Foo
__acl__ = [
]
def __init__(self, parent, name):
self.__parent__ = parent
self.__name__ = name
def __getitem__(self, key):
# get a database connection
s = DBSession()
obj = s.query(Foo).filter_by(id=key).scalar()
if obj is None:
raise KeyError
obj.__parent__ = self
obj.__name__ = key
return obj
class Foo(object):
# this __acl__ is computed dynamically based on the specific object
@property
def __acl__(self):
acls = [(Allow, 'u:%d' % o.id, 'view') for o in self.owners]
return acls
owners = relation('FooOwner')
class Bar(object):
# allow any authenticated user to view Bar objects
__acl__ = [
(Allow, Authenticated, 'view')
]
С такой настройкой вы можете сопоставить шаблоны маршрутов с деревом ресурсов:
config = Configurator()
config.add_route('item_options', '/item/{item}/some_options',
# tell pyramid where in the resource tree to go for this url
traverse='/foos/{item}')
Вам также нужно будет отобразить свой маршрут на определенный вид:
config.add_view(route_name='item_options', view='.views.options_view',
permission='view', renderer='item_options.mako')
отлично, теперь мы можем определить нашу точку зрения и использовать загруженный объект контекста, зная, что если представление выполняется, пользователь имеет соответствующие разрешения!
def options_view(request):
foo = request.context
return {
'foo': foo,
}
используя Эта настройка, вы используете по умолчанию ACLAuthorizationPolicy
, и вы предоставляете разрешения на уровне строк для ваших объектов с отправкой URL. Обратите внимание также, что, поскольку объекты устанавливают __parent__
свойство на детях, политика будет пузыриться вверх по линии, наследуя разрешения от родителей. Этого можно избежать, просто поставив DENY_ALL
ACE в вашем ACL или написав пользовательскую политику, которая не использует родословную контекста.
* обновление * Я перевернул этот пост в фактическую демонстрацию на Github. Надеюсь, это кому-то поможет. https://github.com/mmerickel/pyramid_auth_demo
* обновление * Я написал полный учебник по системе аутентификации и авторизации pyramid здесь:http://michael.merickel.org/projects/pyramid_auth_demo/