金字塔:URL Dispatch(混合)应用程序中的资源树

时间:2017-07-06 13:21:51

标签: python pyramid

我正在尝试在URL Dispatch应用程序中实现动态ACL(包括行级安全性)。 仅定义根工厂似乎不够,因为我需要为每个安全端点执行单独的authz检查。我的设置如下(我使用pyramid docsmmerickel's tutorials作为指南):

config.py

...
settings = config.registry.settings
config = Configurator(settings=settings, root_factory=RootPermissionFactory)
config.set_authentication_policy(CustomAuthenticationPolicy(settings))
config.set_authorization_policy(ACLAuthorizationPolicy())
...

views.py

#import ...

@view_defaults(renderer='json', permission='secured')
class RecordsView(object):
    ...

   @view_config(request_method='GET', route_name='records_by_id')
   def get(self):
        record = self.request.context.data
        if not record:
            return HTTPNotFound()
        return record

    @view_config(request_method='GET', route_name='records')
    def get_by_owners(self):
        owner_uids = self.request.params.mixed()['owner_uids']
        return records_service.get_records(owner_uids=owner_uids)

def includeme(config):
    config.add_route('records', '/records', factory=RecordsResource)
    config.add_route('records_by_id', 'records/{record_id}', factory=RecordFactory, traverse='{record_id}')

authorization.py

class RootPermissionFactory(object):
    __name__ = None
    __parent__ = None

    def __acl__(self):
        return [
            (Allow, 'authenticated_principal', 'secured'),
        ]

    def __init__(self, request):
        self.request = request


class RecordFactory(object):
    def __init__(self, request):
        self.request = request

    def __getitem__(self, key):
        record_data = records_service.get_record(key)
        owner = record_data.get('owner_uid')
        return RecordContext(self.request, owner, record_data)


class RecordContext(object):
    def __acl__(self):    
        owner_principal = 'u:{owner}'.format(owner=self.owner)
        return [
            (Allow, owner_principal, 'secured'),
        ]

    def __init__(self, request, owner, record_data):
        self.request = request
        self.owner = owner
        self.data = record_data


class RecordsResource(object):
    def __acl__(self):
        request_params = self.request.params.mixed()
        request_owner_uids = request_params['owner_uids']
        authorized_owner_uids = owners_api_service.get_authorized_owners(self.request.user['auth_data'])
        return [(Allow, 'authenticated_principal', 'secured')]\
            if set(authorized_owner_uids) == set(request_owner_uids) else []

    def __init__(self, request):
        self.request = request

我的问题如下:

  • 在没有Model层的情况下使用行级安全检查是否可以接受?即没有为记录数据设置ORM,也没有普通模型可以将持久数据放入,因此我必须使用'假'RecordContext类来附加__acl__规则并将数据传递给图
  • /records端点视为资源是否可以接受,尽管它不是来自Traversal透视图的资源,而是依赖于查询参数而不是路径部分?

1 个答案:

答案 0 :(得分:0)

我认为你的两个问题的答案是:如果它适合你,那么它是完全可以接受的。我已经发现很多成功将URL作为资源作为一般模式处理,以至于我有一些工具可以避免使用route_name。例如:

config.add_route('records', '/records', factory=RecordsResource, use_global_views=True)
config.add_route('records_by_id', 'records/{record_id}', factory=RecordFactory, traverse='{record_id}', use_global_views=True)

@view_config(context=RecordsResource, renderer='json')
def records_view(request):
    return {}

@view_config(context=RecordContext, renderer='json')
def record_view(request):
    return {}