Кажется, ответ должен заключаться в использовании view_execution_permitted(context, request, name=''), но я не могу заставить его работать с произвольным именем представления, так как аргумент name
не соответствует значению cornice.service.name
.
Однако вот полурешение из Pyramid issue на Github . Вам понадобится несколько импортов, чтобы связанное решение работало (лучше). Вот полный код
from pyramid.security import _get_registry, Allowed
from pyramid.interfaces import IRouteRequest, IRequest, IViewClassifier, ISecuredView, IView
from zope.interface import providedBy
def route_view_execution_permitted(context, request, route_name, name=''):
reg = _get_registry(request)
context_iface = providedBy(context)
request_iface = reg.queryUtility(
IRouteRequest,
name=route_name,
default=IRequest)
provides = (IViewClassifier, request_iface, context_iface)
view = reg.adapters.lookup(provides, ISecuredView, name=name)
if view is None:
view = reg.adapters.lookup(provides, IView, name=name)
if view is None:
raise TypeError('No registered view satisfies the constraints. '
'It would not make sense to claim that this view '
'"is" or "is not" permitted.')
return Allowed(
'Allowed: view name %r in context %r for route %r (no permission defined)' %
(name, context, route_name))
return view.__permitted__(context, request)
Можно использовать приведенную выше функцию, чтобы определить, может ли текущий пользователь (определенный из объекта request
) получить доступ к службе (по имени) следующим образом:
from cornice import service
services = service.get_services()
for svc in services:
view_permitted = route_view_execution_permitted(request.context, request, svc.name)
if view_permitted == True:
# Do something interesting...
Я обнаружил, что приведенное выше решение имеет два недостатка:
- Это медленно, потому что каждая итерация цикла
svc
по какой-то причине открывает новое соединение с API.
- Он возвращает ошибочные результаты (например, говорит, что у одного есть разрешение на услуги, которых у него нет, и наоборот)
Возможно, кто-то увидит способ улучшить ответ выше. А пока вот решение, использующее ACL, прикрепленные к каждой службе, а затем определяющее, соответствует ли текущий request.effective_principals
.
# Now see if current user meets ACL requirements for any permission
is_permitted = None # set our default.
for ace in acl:
for principal in request.effective_principals:
if ace[1] == principal:
is_permitted = True if ace[0] == Allow else False
break
if is_permitted is not None:
break
if is_permitted is True:
# Do something interesting...
Слабыми сторонами здесь являются:
- Это медленно по той же причине, что и предыдущее решение
- В реализованном виде он рассматривает только
@resource
классы обслуживания, а не методы @view
, которые могут иметь собственные разрешения или списки управления доступом.
Это можно исправить с помощью чего-то вроде:
for method, view, args in service.definitions:
if 'permission' in args:
# Now start looking at permission to see if they match what's given by the parent ACL in the resource class
# Also, the special "__no_permission_required__" value means we should not have a Security Requirement Object
if args['permission'] == NO_PERMISSION_REQUIRED :
# Interesting....
person
hamx0r
schedule
16.06.2015