I have a pyramid projects, with 2 parts:
/_hq/
requires authentication by a login page/_rest/
requires RESTful authentication (through HTTP Basic/Digest Authentication)So, I add the route with 2 main resource factories: HQFactory and RESTFactory. I've built a authentication policy switcher to switch AuthenticationPolicy per resource. It worked.
I use ACLAuthorizationPolicy too.
For each request, I want to return a login page or 401 HTTP Status depends on what resource factory is being accessed.
My problem is I can do @forbidden_view_config for only one view. How can I specify for bidden view per resource factory or another solution for my problems?
Thank you
The simplest way is Michael Merickel's answer (you can see it below). There's another way here:
Deprecated
I solved my problem by using custom_predicates arg from view_config. This is it.
I created a function as a custom predicate:
def resource_factory_predicate(factory):
def check_factory(context, request):
return isinstance(request.context, factory)
return check_factory
Then, here's my views.py
# views.py
@forbidden_view_config(
custom_predicates=(resource_factory_predicate(RootFactory),))
def login_required(request):
userid = authenticated_userid(request)
if userid is not None:
return HTTPForbidden("You're not authorized for this action")
# redirect to login page
@forbidden_view_config(renderer='json',
custom_predicates=(resource_factory_predicate(RESTfulFactory),))
def http_403_unauthenticated(request):
request.response.status = 403
return {
'status': 0,
'message': 'Forbidden',
}
While you cannot dispatch an exception view based on the context (the exception is used as the context) it is possible to cheat and use the containment
option which requires that the specified type is in the lineage
of the actual context. This means it will also match if any context below it raises the exception, affecting an entire subtree of your traversal hierarchy.
@forbidden_view_config(containment=MyRootA)
def root_a_forbidden(exc, request):
# note that the actual context is available on request.context
pass
@forbidden_view_config(containment=MyRootB)
def root_b_forbidden(exc, request):
pass