我正在尝试在URL Dispatch应用程序中实现动态ACL(包括行级安全性)。 仅定义根工厂似乎不够,因为我需要为每个安全端点执行单独的authz检查。我的设置如下(我使用pyramid docs和mmerickel'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
我的问题如下:
RecordContext
类来附加__acl__
规则并将数据传递给图/records
端点视为资源是否可以接受,尽管它不是来自Traversal透视图的资源,而是依赖于查询参数而不是路径部分?答案 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 {}