【发布时间】: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 以将它们复制到子工厂。
这样,如果必须在所有视图中更改某些内容,则根本没有冗余。
【问题讨论】: