金字塔授权存储物品

发布于 2024-11-03 03:08:20 字数 209 浏览 0 评论 0原文

我正在尝试创建一个考虑“项目”所有权的授权策略。例如,某个用户 X“拥有”项目 A、B、C。这些项目可通过 /item/{item}/some_options 等 URL 访问。

如何将有关 {item} 的信息获取到授权策略对象(permits() 调用)?将附加信息放入上下文中是一个好主意(我只进行基于路由的路由)。我该怎么做呢?

I'm trying to create an authorization policy that takes "item" ownership into account. For example some user X "owns" items A, B, C. Those are accessed via URLs like /item/{item}/some_options.

How can I get the information about {item} to the authorization policy object (permits() call)? Is putting additional information into context a good idea (I'm doing routes-based routing only). How would I do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦魇绽荼蘼 2024-11-10 03:08:20

您可以通过使用为此目的设计的自定义资源树,将 ACLAuthorizationPolicy 与 URL Dispatch 结合使用来执行此操作。

例如,您拥有 Foo 对象的权限和 Bar 对象的权限。可以通过使用 url 遍历资源树来找到这些 ACL:

/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 Dispatch 为对象提供行级权限。另请注意,由于对象在子对象上设置了 __parent__ 属性,因此该策略将冒泡沿袭,继承父对象的权限。只需在 ACL 中添加 DENY_ALL ACE 或编写不使用上下文沿袭的自定义策略即可避免这种情况。

* 更新 *
我已将这篇文章变成了 Github 上的实际演示。希望它能帮助某人。
https://github.com/mmerickel/pyramid_auth_demo

* 更新 *
我在这里编写了有关金字塔身份验证和授权系统的完整教程:http://michael.merickel.org /projects/pyramid_auth_demo/

You can do this using the ACLAuthorizationPolicy combined with URL Dispatch by using a custom resource tree designed for this purpose.

For example, you have permissions for Foo objects, and permissions for Bar objects. These ACLs can be found by traversing the resource tree using the urls:

/foos/{obj}
/bars/{obj}

Your resource tree then becomes a hierarchy of permissions, where at any point in the tree you can place an __acl__ on the resource object:

root                       (Root)
|- foos                    (FooContainer)
|  `- {obj}                (Foo)
`- bars                    (BarContainer)
   `- {obj}                (Bar)

You can represent this hierarchy in a resource tree:

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')
    ]

With a setup like this, you can then map route patterns to your resource tree:

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}')

You will also need to map your route to a specific view:

config.add_view(route_name='item_options', view='.views.options_view',
                permission='view', renderer='item_options.mako')

Great, now we can define our view and use the loaded context object, knowing that if the view is executed, the user has the appropriate permissions!

def options_view(request):
    foo = request.context
    return {
        'foo': foo,
    }

Using this setup, you are using the default ACLAuthorizationPolicy, and you are providing row-level permissions for your objects with URL Dispatch. Note also, that because the objects set the __parent__ property on the children, the policy will bubble up the lineage, inheriting permissions from the parents. This can be avoided by simply putting a DENY_ALL ACE in your ACL, or by writing a custom policy that does not use the context's lineage.

* Update *
I've turned this post into an actual demo on Github. Hopefully it helps someone.
https://github.com/mmerickel/pyramid_auth_demo

* Update *
I've written a full tutorial around pyramid's authentication and authorization system here: http://michael.merickel.org/projects/pyramid_auth_demo/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文