金字塔 "per object" 权限
Pyramid "per object" permissions
我正在尝试为我正在构建的应用程序工具箱创建一个安全系统。我以前有一个 acl,但问题是我无法控制基于应用程序的级别。
我认为下图描述了我如何在数据库中设置它。
基本上,我 认为 我需要的是将应用程序 GUID 传递给 groupfinder()
function,我不确定我应该如何处理这个。
有人有什么想法吗?
Pyramid 中的 groupfinder
和 context factory
旨在单独和隔离地运行。前者用来定义"current user",后者用来定义"current resource"。这两项最后通过授权策略的permits
函数与一个permission
结合,判断"current user"是否有"permission"对这个"resource"进行操作。
groupfinder
负责识别用户。这意味着将它们转换成一组可以稍后使用的主体。
context factory
确定当前资源(上下文)...所以这通常应该根据 url 不同(记住 URL 中的 R 是资源) 所以 url 通常定义资源。
附加到 url 的视图定义了所需的 permission
(对于视图执行的操作)。
这里的第2步是来金字塔的人最难理解的地方。如何为每个 URL 定义此资源?它在 url 调度教程 [1] 中有所介绍,但我将在此处快速解释。
正如我上面所说,每条路线通常代表一个资源,因此我们可以通过为该路线定义一个对象来将其放入代码中。这是通过 config.add_route(..., factory=...)
的 factory
参数完成的,它可以用路由做很多事情来确定当前资源是什么。
def page_factory(request):
# I'm attached to a page so I can grab the matchdict
pageid = request.matchdict['pageid']
page = request.db.query(Page).get(pageid)
if page is None:
raise HTTPNotFound
return page
config.add_route('page', '/pages/{pageid}', factory=page_factory)
此代码段定义了一个带有页面工厂的路由,附加到此路由的每个视图都将页面作为上下文 (request.context
)。
此处的 Page
对象有一个 ACL,定义了 users/groups(委托人)可以对其执行的操作(权限)。
class Page(Base):
__tablename__ = 'page'
# a bunch of columns
def __acl__(self):
return [
(Allow, f'app:{self.app.id} user:{self.owner_id}', 'edit'),
(Allow, f'app:{self.app.id}', 'read'),
]
假设此页面附加到 app1,我们可以轻松定义一个 groupfinder,表示 app1 中的任何人都可以阅读它:
def groupfinder(userid, request):
user = request.db.query(User).get(userid)
if user is not None:
principals = []
for app in user.apps:
principals += [
f'app:{app.id}',
f'app:{app.id} user:{user.id}',
]
for group in app.groups:
principals += [f'app:{app.id} group:{group.id}']
return principals
groupfinder 不知道页面,但它以足够的粒度描述用户,页面可以将它们与它允许的操作相匹配。
[1] https://docs.pylonsproject.org/projects/pyramid/en/1.9-branch/tutorials/wiki2/authorization.html
我正在尝试为我正在构建的应用程序工具箱创建一个安全系统。我以前有一个 acl,但问题是我无法控制基于应用程序的级别。
我认为下图描述了我如何在数据库中设置它。
基本上,我 认为 我需要的是将应用程序 GUID 传递给 groupfinder()
function,我不确定我应该如何处理这个。
有人有什么想法吗?
Pyramid 中的 groupfinder
和 context factory
旨在单独和隔离地运行。前者用来定义"current user",后者用来定义"current resource"。这两项最后通过授权策略的permits
函数与一个permission
结合,判断"current user"是否有"permission"对这个"resource"进行操作。
groupfinder
负责识别用户。这意味着将它们转换成一组可以稍后使用的主体。context factory
确定当前资源(上下文)...所以这通常应该根据 url 不同(记住 URL 中的 R 是资源) 所以 url 通常定义资源。附加到 url 的视图定义了所需的
permission
(对于视图执行的操作)。
这里的第2步是来金字塔的人最难理解的地方。如何为每个 URL 定义此资源?它在 url 调度教程 [1] 中有所介绍,但我将在此处快速解释。
正如我上面所说,每条路线通常代表一个资源,因此我们可以通过为该路线定义一个对象来将其放入代码中。这是通过 config.add_route(..., factory=...)
的 factory
参数完成的,它可以用路由做很多事情来确定当前资源是什么。
def page_factory(request):
# I'm attached to a page so I can grab the matchdict
pageid = request.matchdict['pageid']
page = request.db.query(Page).get(pageid)
if page is None:
raise HTTPNotFound
return page
config.add_route('page', '/pages/{pageid}', factory=page_factory)
此代码段定义了一个带有页面工厂的路由,附加到此路由的每个视图都将页面作为上下文 (request.context
)。
此处的 Page
对象有一个 ACL,定义了 users/groups(委托人)可以对其执行的操作(权限)。
class Page(Base):
__tablename__ = 'page'
# a bunch of columns
def __acl__(self):
return [
(Allow, f'app:{self.app.id} user:{self.owner_id}', 'edit'),
(Allow, f'app:{self.app.id}', 'read'),
]
假设此页面附加到 app1,我们可以轻松定义一个 groupfinder,表示 app1 中的任何人都可以阅读它:
def groupfinder(userid, request):
user = request.db.query(User).get(userid)
if user is not None:
principals = []
for app in user.apps:
principals += [
f'app:{app.id}',
f'app:{app.id} user:{user.id}',
]
for group in app.groups:
principals += [f'app:{app.id} group:{group.id}']
return principals
groupfinder 不知道页面,但它以足够的粒度描述用户,页面可以将它们与它允许的操作相匹配。
[1] https://docs.pylonsproject.org/projects/pyramid/en/1.9-branch/tutorials/wiki2/authorization.html