Source code for flask_allows.views

from functools import wraps

from flask import current_app, request

from .allows import allows

__all__ = ("requires", "exempt_from_requirements", "guard_entire")


def _get_executing_handler():
    return current_app.view_functions[request.endpoint]


def _should_run_requirements():
    if request.routing_exception is not None:
        return False

    return not getattr(_get_executing_handler(), "__allows_exempt__", False)


[docs]def requires(*requirements, **opts): """ Standalone decorator to apply requirements to routes, either function handlers or class based views:: @requires(MyRequirement()) def a_view(): pass class AView(View): decorators = [requires(MyRequirement())] :param requirements: The requirements to apply to this route :param throws: Optional. Exception or exception instance to throw if authorization fails. :param on_fail: Optional. Value or function to use when authorization fails. :param identity: Optional. An identity to use in place of the currently loaded identity. """ identity = opts.get("identity") on_fail = opts.get("on_fail") throws = opts.get("throws") def decorator(f): @wraps(f) def allower(*args, **kwargs): result = allows.run( requirements, identity=identity, on_fail=on_fail, throws=throws, f_args=args, f_kwargs=kwargs, ) # authorization failed if result is not None: return result return f(*args, **kwargs) return allower return decorator
[docs]def exempt_from_requirements(f): """ Used to exempt a route handler from ambient requirement handling unless it is explicitly decorated with a requirement runner:: @bp.route('/') @exempt_from_requirements def greeting_area(): return "Hello!" To use with a class based view, apply it to the class level decorators attribute:: class SomeCBV(View): decorators = [exempt_from_requirements] def get(self): return "Hello!" .. note:: You cannot exempt individual methods of a class based view with this decorator, e.g. the follow will not work:: class SomeCBV(MethodView): @exempt_from_requirements def get(self): return "Hello!" Any permissioning applied at the blueprint level would still affect this route. :param f: The route handler to be decorated. .. versionadded:: 0.7.0 """ f.__allows_exempt__ = True return f
[docs]def guard_entire(requirements, identity=None, throws=None, on_fail=None): """ Used to protect an entire blueprint with a set of requirements. If a route handler inside the blueprint should be exempt, then it may be decorated with the :func:`~flask_allows.views.exempt_from_requirements` decorator. This function should be registered as a before_request handler on the blueprint and provided with the requirements to guard the blueprint with:: my_bp = Blueprint(__name__, 'namespace') my_bp.before_request(guard_entire(MustBeLoggedIn())) ``identity``, ``on_fail`` and ``throws`` may also be provided but are optional. If on_fails returns a non-None result, that will be considered the return value of the routing:: from flask import flash, redirect def flash_and_redirect(message, level, endpoint): def _(*a, **k): flash(message, level) return redirect(endpoint) return _ bp = Blueprint(__name__, 'namespace') bp.before_request( guard_entire( [MustBeLoggedIn()], on_fail=flash_and_redirect( "Please login in first", "warning", "login" ) ) ) ``on_fail`` will also receive anything found in ``flask.request.view_args`` as keyword arguments. If needed, this guard may be applied multiple times. This may be useful if different conditions should result in different `on_fail` mechanisms being invoked:: bp = Blueprint(__name__, "admin_panel") bp.before_request( guard_entire( [MustBeLoggedIn()], on_fail=flash_and_redirect( "Please login in first", "warning", "login" ) ) ) bp.before_request( guard_entire( [MustBeAdmin()], on_fail=flash_and_redirect( "You are not an admin.", "danger", "index" ) ) ) :param requirements: An iterable of requirements to apply to every request routed to the blueprint. :param identity: Optional. The identity that should be used for fulfilling requirements on the blueprint level. :param throws: Optional. Exception or exception type to be thrown if authorization fails. :param on_fail: Optional. Value or function to use if authorization fails. .. versionadded: 0.7.0 """ def guarder(): if _should_run_requirements(): return allows.run( requirements, identity=identity, on_fail=on_fail, throws=throws, f_kwargs=request.view_args, ) return None return guarder