金字塔:检查路线名称的权限

时间:2014-01-04 21:04:41

标签: python python-2.7 permissions pyramid

金字塔中某个资源的许可是not hard to check。我想知道如何确定权限类型和与某条路由相对应的资源。

详细信息。假设我添加了路径

config.add_route('resource.edit', '/t/{resource_id:\d+}/edit',
    factory = FactoryFactory('resource') ))

其中FactoryFactory是返回工厂的函数。在这种情况下,无论可能是什么,它都会返回“resources”的工厂。后来,我这样说:

@view_config(
    route_name='resource.edit',
    renderer='resource-edit.pt',
    permission='edit'
)
def edit(resource_object, request):
    ...

在某些时候,我会在网站上生成一个链接到

的输入元素
request.route_url('resource.edit', resource_id=some_input)

编辑:根据要求,我会向您提供确切的模板代码,希望这可以让您更好地了解情况。我们使用的模板引擎是Chameleon。

    <a href="${request.route_url('resource.edit', resource_id=res.id)}" 
       class="btn btn-info morespacing"><i class="icon-edit"></i>edit</a>

现在我想要的是这样的:

    <a tal:condition="h.route_accessible(request, 'resource.edit', res.id)" 
       href="${request.route_url('resource.edit', resource_id=res.id)}" 
       class="btn btn-info morespacing"><i class="icon-edit"></i>edit</a>

换句话说:如果用户有权首先执行编辑操作,我想显示此输入元素


现在,我可以举一个例子说明哪些方法有效但对我没有吸引力,因为它不灵活。我编写了一个辅助函数

def can_edit(request, factory_type, res_id):
    resource = FactoryFactory(factory_type)(res_id)
    return has_permission('edit', resource, request)

然后我写

    <a tal:condition="h.can_edit(request, 'resource', res.id)" 
       href="${request.route_url('resource.edit', resource_id=res.id)}" 
       class="btn btn-info morespacing"><i class="icon-edit"></i>edit</a>

这对我来说没什么吸引力,因为关于工厂有关权限的信息已被编码到路径中,所以我觉得我应该能够通过简单地提供它来访问它路线的名称


因此,我正在寻找一种方法来获取资源和来自的权限路径信息,即来自字符串'resource.edit'和资源ID some_input。这可能吗?如果是,怎么样?

提前非常感谢你。

5 个答案:

答案 0 :(得分:3)

问题:

  

因此,我正在寻找一种获取资源的方法   仅来自路线信息的许可,即来自字符串的许可   &#39; resource.edit&#39;和资源id some_input。这可能吗?如果   是的,怎么样?

Pyramid无法知道用户(当前请求)是否能够在您提供资源之前访问您的资源。你可以参考

Assigning ACLs to your Resource Objects

正如您所看到的,Pyramid将查看资源对象的__ACL__属性(以及资源​​的祖先的__ACL__),然后确定谁拥有对此资源的哪种权限,因此,这是不可能的使用金字塔默认授权策略。

要解决您的问题,您可以自定义AuthorizationPolicy,制定自己的授权规则,也可以轻松地从ID创建资源。

考虑一下,如果资源的相应表有一个owner字段,并且需要检查当前用户是否是特定资源的所有者,那么无论如何都需要从数据库获取该资源。所以你需要创建一个提供__ACL__属性的资源。所以,我的建议是,让创建资源变得更容易,使它像Resource(res.id)这样,这样你就可以像这样编写你的模板

<a tal:condition="has_permission('edit', Resource(res.id), request)" 
   href="${request.route_url('resource.edit', resource_id=res.id)}" 
   class="btn btn-info morespacing"><i class="icon-edit"></i>edit</a>

更新

然后我认为您需要使用introspector来获取工厂并创建像这样的资源

def has_permission_for_route(request, route_name, permission, res_id):
    introspector = request.registry.introspector
    route_name = request.matched_route.name
    route_intr = introspector.get('routes', route_name)
    factory = route_intr['factory']

    resource = factory(request, res_id=res_id)
    return has_permission(permission, resource, request)

答案 1 :(得分:3)

如果你想从路线中提取工厂 - 使用金字塔内省

@view_config(route_name='bar')
def show_current_route_pattern(request):
    introspector = request.registry.introspector
    route_name = request.matched_route.name
    route_intr = introspector.get('routes', route_name)
    factory = route_intr['factory'])
    ...

详细了解内省here

答案 2 :(得分:1)

回答你的问题:不,你没有从路线获得有关许可的信息。路线只匹配视图。可以使用许多不同方式使用权限保护视图和资源。您的安全策略通常与用户,资源和视图相关,而不是与路由相关。

可能这个建议对你有任何帮助。

给定资源的这条路线

config.add_route('resource.view', '/t/{resource_id:\d+}',
    factory = FactoryFactory('resource') ))

您创建一个匹配此路线的视图。路线工厂将制作资源作为上下文。 在视图中封装与权限相关的代码

@view_config(
    route_name='resource.view',
    renderer='resource-view.pt',
    permission='view'
)
def view_page(resource_object, request):
    can_edit = has_permission('edit', resource_object, request)

    #do some more stuff - extend the dictionary passed to the renderer
    ...

    return dict(
        res = resource_object,
        can_edit = can_edit,
    )

在模板中使用'can_edit'来控制此链接或任何其他标记的可见性。

<a tal:condition="can_edit"
   href="${request.route_url('resource.edit', resource_id=res.id)}" 
   class="btn btn-info morespacing"><i class="icon-edit"></i>edit</a>

您可以通过计算URL来改进示例,以便在视图代码中编辑资源。

@view_config(
    route_name='resource.view',
    renderer='resource-view.pt',
    permission='view'
)
def view_page(resource_object, request):
    can_edit = has_permission('edit', resource_object, request)
    edit_url = request.route_url('resource.edit', resource_id=resource_object.id)

    #do some more stuff - extend the dictionary passed to the renderer
    ...

    return dict(
        can_edit = can_edit,
        edit_url = edit_url,
    )

这导致了紧凑的模板代码并提高了视图代码的可测试性。

<a tal:condition="can_edit" 
   href="${edit_url}" 
   class="btn btn-info morespacing"><i class="icon-edit"></i>edit</a>

为了使代码对任何金字塔开发者更常见,我想使用framework选项从请求中获取上下文。

@view_config(
    route_name='resource.view',
    renderer='resource-view.pt',
    permission='view'
)
def view_page(request):
    context = request.context
    can_edit = has_permission('edit', context, request)
    edit_url = request.route_url('resource.edit', resource_id=context.id)

    #do some more stuff - extend the dictionary passed to the renderer
    ...

    return dict(
        can_edit = can_edit,
        edit_url = edit_url,
    )

关于您的申请,我想推荐这些金字塔样本应用程序:

答案 3 :(得分:0)

你曾经使用过......

http://ziggurat-foundations.readthedocs.org/en/latest/

在此范围内,您可以轻松测试特定的用户权限,因此您可以在模板或代码中轻松过滤用户权限。

t = session.query(UserPermission).\
    filter(UserPermission.user_id == 'userid').\
    filter(UserPermission.perm_name == 'yourpermission')).first()

然后在模板(显示的Jinja2示例)中,您可以执行以下操作:

{% if t %}
    <!-- show edit link -->
{% endif %}

或者,如果您正在进行用户查询,则可以将加入与当前查询联系起来。

答案 4 :(得分:0)

您可以将权限存储在资源上(持久性或仅作为类的attr):

def dynamic_resource_permission(context, request):
    permission = getattr(context, 'view_permission', 'view')
    if not has_permission(context, permission):
        raise HTTPForbidden()
    return True

@view_config(
  route_name='resource.edit',
  renderer='resource-edit.pt',
  permission='edit',
  custom_predicates=(dynamic_resource_permission,),
)
def edit(resource_object, request):
    ....

PS:我没有运行上面的内容,但上面的一些变体应该有效。