金字塔:URL 调度(混合)应用程序中的资源树
Pyramid: resource tree in URL Dispatch(hybrid) application
我正在尝试在 URL Dispatch 应用程序中实施动态 ACL(包括行级安全性)。
仅定义根工厂似乎还不够,因为我需要为每个安全端点执行单独的 authz 检查。我的设置如下(我使用 pyramid docs and 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
我的问题如下:
- 在没有模型层的情况下使用行级安全检查是否可以接受?也就是说,没有为记录数据设置 ORM,也没有普通模型可以将持久数据放入其中,所以我必须使用 'fake'
RecordContext
class 附加 __acl__
规则并将数据传递给视图
- 将
/records
端点视为资源是否可以接受,尽管从遍历的角度来看它不是资源并且依赖于查询参数而不是路径部分?
我认为您的两个问题的答案是:如果它适合您,那么它是完全可以接受的。我发现很多成功地将 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 {}
我正在尝试在 URL Dispatch 应用程序中实施动态 ACL(包括行级安全性)。 仅定义根工厂似乎还不够,因为我需要为每个安全端点执行单独的 authz 检查。我的设置如下(我使用 pyramid docs and 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
我的问题如下:
- 在没有模型层的情况下使用行级安全检查是否可以接受?也就是说,没有为记录数据设置 ORM,也没有普通模型可以将持久数据放入其中,所以我必须使用 'fake'
RecordContext
class 附加__acl__
规则并将数据传递给视图 - 将
/records
端点视为资源是否可以接受,尽管从遍历的角度来看它不是资源并且依赖于查询参数而不是路径部分?
我认为您的两个问题的答案是:如果它适合您,那么它是完全可以接受的。我发现很多成功地将 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 {}