如何限制基于URL的单页ID权限?(How do I restrict permissions ba

2019-07-29 02:24发布

我想实现我的网站金字塔的安全功能,但我有一些麻烦搞清楚如何使用它。

我一直在阅读了本教程和这个例子中 ,以及在金字塔的文档,我无法弄清楚如何实现单页ID的授权策略。

例如,我有以下URL方案:

/pages
/pages/12

/pages明显列出了可用的页面和/pages/:id在这里你可以阅读网页上/评论。

文档/例子我读过表明,你可以通过提供一个实现了组级ACS的groupfinder回调与组的列表。 如editoradmin ,等等。

我怎么能不使用基于页面ID为权限和权利,而不是一组?

在我上面的URL方案,当用户浏览到/pages ,他们必须先登录当他们浏览到。 /pages/:id ,他们必须已获得访问,查看特定的ID。 或者,他们必须是页面的所有者。

相同的意见。 在/page/:id页面,他们可能已经获准进入浏览网页,但它没有发表评论。

Answer 1:

这里的基本原则是,金字塔的安全检查机器在当前背景下的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而不是页面实例,所以这个观点不会被金字塔使用。 其结果是金字塔会自动产生一个未发现的错误。



Answer 2:

为了讨论的目的,我会假设你正在使用的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。 唉,我离题了,因为这不是你要找的事情。 希望这回答了你的问题。



文章来源: How do I restrict permissions based on the single page ID in the URL?