我想实现我的网站金字塔的安全功能,但我有一些麻烦搞清楚如何使用它。
我一直在阅读了本教程和这个例子中 ,以及在金字塔的文档,我无法弄清楚如何实现单页ID的授权策略。
例如,我有以下URL方案:
/pages
/pages/12
/pages
明显列出了可用的页面和/pages/:id
在这里你可以阅读网页上/评论。
文档/例子我读过表明,你可以通过提供一个实现了组级ACS的groupfinder
回调与组的列表。 如editor
, admin
,等等。
我怎么能不使用基于页面ID为权限和权利,而不是一组?
在我上面的URL方案,当用户浏览到/pages
,他们必须先登录当他们浏览到。 /pages/:id
,他们必须已获得访问,查看特定的ID。 或者,他们必须是页面的所有者。
相同的意见。 在/page/:id
页面,他们可能已经获准进入浏览网页,但它没有发表评论。
这里的基本原则是,金字塔的安全检查机器在当前背景下的ACL。 在这种情况下,你的页面将是合乎逻辑的情况下使用。 第一步是设置一个上下文工厂的页面。 假设你正在使用的SQLAlchemy和URL调度,这是简单的事情。 注册这样的路线:
config.add_route('page', '/pages/{id:\d+}', factory=page_factory)
有一个在路径中的小把戏,使金字塔检查页ID必须是数字,所以你不必检查自己的路线。 注意参照* page_factory *方法。 现在,让我们定义:
def page_factory(request):
return DBSession.query(Page).get(int(request.matchdict['id']))
这需要从路由的页ID,并使用该查找的页面在你的数据库。 请注意,我们不检查ID可以转换为这里的整数:我们可以逃脱,自路线已检查直接。
下一步是设置页面上的ACL。 最简单的方法是将ACL属性添加到您Page类:
from pyramid import security
class Page(BaseObject):
@property
def __acl__(self):
return [(security.Allow, self.userid, 'view')]
这个ACL告诉只存储在page.userid的ID的用户被允许查看该页面的金字塔。 重要的是要在这里实现的是,ACL是每个页面不同:它是为分别根据数据库中的信息的每一页生成的; 在这种情况下使用self.userid。
您现在可以使用的查看权限上的看法:
@view_config(route_name='page', context=Page, permission='view')
def page_view(context, request):
return 'I can see!'
这个例子有一个页面一个很小的ACL,但你可以扩展以满足您的需求。
另请注意view_config上下文= page参数:这告诉金字塔,这种观点只应使用的上下文是一个页面。 如果上下文工厂(page_factory在这个例子中)没有找到匹配的页面会返回None而不是页面实例,所以这个观点不会被金字塔使用。 其结果是金字塔会自动产生一个未发现的错误。
为了讨论的目的,我会假设你正在使用的SQLAlchemy与数据库进行交互。
如果你有config.add_route('pages', '/pages/{id}')
在您的__init__.py
,您可以添加自定义原厂更换/补充默认的ACL。 例如:
您当前的ACL可以是这样的:
class RootFactory(object):
__acl__ = [
(Allow, Everyone, 'view'),
(Allow, Authenticated, 'auth'),
]
def __init__(self, request):
self.request = request
这将允许通过验证的用户与访问您的网站“视图”的权限访问任何视图“权威性”的许可,任何人都访问任何看法。
通过使用自定义的工厂 ,你可以绕过你RootFactory,或补充。
要绕过 ,更改原始config.add_route到- > config.add_route('pages', '/pages/{id}', factory=PageFactory)
并创建一个PageFactory类是这样的:
class PageFactory(object):
__acl__ = [
(Allow, Everyone, 'view'),
(Allow, Authenticated, 'auth'),
]
def __init__(self, request):
self.request = request
from pyramid.security import authenticated_userid
user_id = authenticated_userid(self.request)
thispage = DBSession.query(Page).filter(Page.id==self.request.matchdict['id']).first()
if thispage.user_id == user_id:
## Pyramid allows Everyone, Authenticated, and authenticated_userid
## (each of these is known as a Principal) to be in the second
## position of the ACL tuple
acl.append((Allow, user_id, 'edit'))
这是假设你的观点有permission='edit'
作为它的参数之一。
现在,如果你想使用RootFactory,并与您的自定义工厂 补充进去,所以你不必重复自己,只要离开你RootFactory正如我在这篇文章的开头显示,从RootFactory类继承, 因此:
class PageFactory(RootFactory):
@property
def __acl__(self):
acl = super(PageFactory, self).__acl__[:] ##[:] creates a copy
from pyramid.security import authenticated_userid
user_id = authenticated_userid(self.request)
thispage = DBSession.query(Page).filter(Page.id==self.request.matchdict['id']).first()
if thispage.user_id == user_id:
acl.append((Allow, user_id, 'edit'))
return acl
该groupfinder是非常有用的,顺便说一下,因为这样你可以简单地将在组中的用户,例如“管理员”,以及所有那些管理员组可以访问视图permission='whatever'
或permission='whateverelse'
你可能想和一个返回当前用户群组列表没有工厂需要的,只是一个groupfinder。 唉,我离题了,因为这不是你要找的事情。 希望这回答了你的问题。