【问题标题】:Pyramid ACL without traversal没有遍历的金字塔 ACL
【发布时间】:2011-12-14 08:48:40
【问题描述】:

我真的不知道 ACL 是如何工作的。我知道这很酷,可以为我节省很多时间和痛苦。但目前我有点迷路了。金字塔的所有示例都使用遍历。我专门使用 URL Dispatch。我不确定如何构建资源树结构。

这是一个代码示例:

class QuestionFactory(object):

    def __init__(self, request):
        self.__acl__ = default[:]
        self.uid = authenticated_userid(request)

        self.qid = request.matchdict.get('id')
        if self.qid:
            self.question = request.db.questions.find_one({'_id': ObjectId(self.qid)})
            if str(self.question.get('owner')) == self.uid:
                self.__acl__.append((Allow, userid, 'view'))     

问题是,它有效。但我必须为每种类型的资源定义一个新工厂。我不确定我应该如何知道我试图通过 URL Dispatch 和 Factory 访问哪个资源。我会看到类似的东西

/accounts/{account}   //Owners only but viewable by anyone 
/messages/{message}   //Owners only
/configs/{config}     //Admin only
/pages/{page}         //Admins only but viewable by anyone

这里说我会有这样的结构

  Root -\
         +-- account
         +-- message
         +-- config
         +-- page

每个工厂都有自己的特殊 acl。另一件事是 /accounts 是主页。它没有 id 或任何东西。另外 /accounts/new 也是一个特例。它不是 id,而是创建新项目的视图。

我正在使用带有 GET/PUT/DELETE/POST 要求的宁静风格。我不太确定我应该如何将 url 自动匹配到资源和正确的 acl。如果我在根目录中定义一个像上面这样的特殊工厂,就没有问题。

编辑

除了某些事情之外,我确实让它工作了。我终于想我明白遍历的目的是什么了。例如,我们有那个 url:/cmets/9494f0eda/new, /cmets/{comment}/new

我们可能不得不在我们的资源树中创建节点,甚至是 3 个节点。

将首先检查 RootFactory,然后根据我们的遍历。它将获取 RootFactory 的 cmets 属性,然后是 Comment factory 的“comment”和 CommentFactory 或 Object 本身的“new”

我不像 Michael 的例子那样使用 Factory 作为 dict

看起来很像:

class RessourceFactory(object):
    def __init__(self, parent, name):

        self.__acl__ = []
        self.__name__ = name
        self.__parent__ = parent

        self.uid = parent.uid
        self.locale = parent.locale
        self.db = parent.db
        self.req = parent.req

这是我的基础资源对象。在每个步骤中,它都会将信息从父级复制到新的子级。我当然可以冒泡我的属性.. context.parent._parent_.uid 但那是只是没那么好。

我不使用 dict 属性的原因。我添加使其适用于

/cmets

由于某些原因,它确实创建了我的 CommentFactory,但没有返回它,因为不需要密钥。

所以我的根工厂看起来像这样:

class RootFactory(object):

    def __init__(self, request):
        self.__acl__ = default[:]

        self.req = request
        self.db = request.db

        self.uid = authenticated_userid(request)
        self.locale = request.params.get('locale', 'en')

    def __getitem__(self, key):

        if key == 'questions':
            return QuestionFactory(self, 'questions')
        elif key == 'pages':
            return PageFactory(self, 'pages')
        elif key == 'configs':
            return ConfigFactory(self, 'configs')
        elif key == 'accounts':
            return AccountFactory(self, 'accounts')

        return self

如果没有找到项目,RootFactory 返回自己,如果没有,它返回一个新的工厂。由于我的代码基于迈克尔的代码,因此工厂构造函数有第二个参数。我不确定是否保留它,因为 QuestionFactory 很清楚处理“问题”,因此无需在此处命名工厂。它应该已经知道它的名字了。

class QuestionFactory(RessourceFactory):
    def __init__(self, parent, name):
        RessourceFactory.__init__(self, parent, name)
        self.__acl__.append((Allow, 'g:admin', 'view'))
        self.__acl__.append((Allow, 'g:admin', 'edit'))
        self.__acl__.append((Allow, 'g:admin', 'create'))
        self.__acl__.append((Allow, 'g:admin', 'delete'))
        self.__acl__.append((Allow, Everyone, 'create'))

    def __getitem__(self, key):

        if key=='read':
            return self

        self.qid = key
        self.question = self.db.questions.find_one({'_id': ObjectId(self.qid)})

        if str(self.question.get('owner')) == self.uid:
            log.info('Allowd user %s' % self.uid)
            self.__acl__.append((Allow, self.uid, 'view'))
            self.__acl__.append((Allow, self.uid, 'edit'))
            self.__acl__.append((Allow, self.uid, 'delete'))

        return self

这就是几乎所有逻辑的去向。在 init 中,我设置了适用于 getitem 中的 /questions 的 acl,它将适用于 /questions/{id}/*

由于我返回了自身,任何经过此 RessourceFactory 的 getitem 都将指向自身,除非我针对某些特殊情况返回一个新工厂。这样做的原因是我的上下文不仅仅是数据库中的对象或对象。

我的上下文处理多个事情,如用户 ID、语言环境等...当 acl 完成后,我有一个新的上下文对象可供使用。它删除了视图中的大部分逻辑。

我可能可以设置事件来查询语言环境和 uid,但它确实适合这里。如果我需要任何新的东西,我只需要编辑我的 RootFactory 和 RessourceFactory 以将它们复制到子工厂。

这样,如果必须在所有视图中更改某些内容,则根本没有冗余。

【问题讨论】:

    标签: python acl pyramid routes


    【解决方案1】:

    您似乎对某些对象/行级安全功能感兴趣,以便仅允许帐户所有者查看其数据。我会向您推荐我之前关于此主题的 SO 答案,以及我一直在围绕此答案构建的 URL Dispatch 中的身份验证教程。具体来说,您可能希望查看链接的 github 项目中的 2.object_security 演示以及解释资源树的文档,作为我网站上呈现的 html 的一部分。

    Pyramid authorization for stored items

    https://github.com/mmerickel/pyramid_auth_demo

    http://michael.merickel.org/projects/pyramid_auth_demo/

    如果您对了解这些资源有任何疑问,我很乐意在此处进一步详细说明。

    【讨论】:

    • 我不知道,我都已经读过了。正如我在标题中所说......我试图在没有遍历的情况下实现这一目标。我试过一次,它弄乱了我的路线,没有任何效果。我不相信我也有任何树层次结构。因为我有页面、消息等,但没有对象真正相互关联。所以 /foo/bar/baz 这样的事情对我来说没什么意义。
    • 我做了一些测试,毕竟它可能会起作用......我明天会写点东西我明天考试前必须睡觉。
    • 我给你的链接正在使用 URL 调度...金字塔的身份验证系统通过遍历对象树来分层工作。这就是 ACLAuthorizationPolicy 的工作方式。如果您“已经阅读了所有内容”,我会感到惊讶,因为我昨晚刚刚重新编写了那个演示,并且正在积极地进行工作。 ;-)
    • 您简单地使用单节点树(QuestionFactory)的机制是有效的,如果这对您最有意义,那么继续使用它。
    • 好吧,我可能已经读过大部分内容,因为我刚读过它。艰难的工作。我得到了工作,它比我想象的要简单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-22
    • 2011-05-24
    相关资源
    最近更新 更多