From e24e586fa834ceee0332793a6bf2bde09ee98502 Mon Sep 17 00:00:00 2001 From: Mark Gibbs Date: Wed, 26 Dec 2018 09:11:55 -0800 Subject: [PATCH 1/2] Added documentation and sketch of example control for access control through view decoration --- docs/access_control.rst | 78 +++++++++++++++++++++++++++++++++++++++++ docs/configuration.rst | 16 +++++++++ docs/faq.rst | 2 +- docs/index.rst | 3 +- 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 docs/access_control.rst diff --git a/docs/access_control.rst b/docs/access_control.rst new file mode 100644 index 00000000..6ade372e --- /dev/null +++ b/docs/access_control.rst @@ -0,0 +1,78 @@ +.. _access_control: + +View decoration +=============== + +The ``django-plotly-dash`` views, as served by Django, can be wrapped with +an arbitrary decoration function. This allows the use +of the Django `login_required `_ view decorator +as well as enabling more specialised and fine-grained control. + +The ``login_required`` decorator +---------------------------- + +The ``login_required`` decorator from the Django authentication system can be used as a view decorator. A wrapper function is provided +in ``django_plotly_dash.access``. + +.. code-block:: python + + PLOTLY_DASH = { + + ... + # Name of view wrapping function + "view_decorator": "django_plotly_dash.access.login_required", + ... + } + +Note that the view wrapping is on all of the ``django-plotly-dash`` views. + +Fine-grained control +-------------------- + +The view decoration function is called for each variant exposed in +the ``django_plotly_dash.urls`` file. As well as the +underlying view function, each call to the decorator is given the name of the +route, as used by ``django.urls.reverse``, the specific url fragment for the view, and a name +describing the type of view. + +From this information, it is possible to implement view-specific wrapping of the view functions, and +in turn the wrapper functions can then use the request content, along with other information, to control +access to the underlying view function. + +.. code-block:: python + + from django.views.decorators.csrf import csrf_exempt + + def check_access_permitted(request, **kwargs): + # See if access is allowed; if so return True + # This function is called on each request + + ... + + return True + + def user_app_control(view_function, name=None, **kwargs): + # This function is called on the registration of each django-plotly-dash view + # name is one of main component-suites routes layout dependencies update-component + + def wrapped_view(request, *args, **kwargs): + is_permitted = check_access_permitted(request, **kwargs) + if not is_permitted: + # Access not permitted, so raise error or generate an appropriate response + + ... + + else: + return view_function(request, *args, **kwargs) + + if getattr(view_function,"csrf_exempt",False): + return csrf_exempt(wrapped_view) + + return wrapped_view + +The above sketch highlights how access can be controlled based on each request. Note that the +``csrf_exempt`` property of any wrapped view is preserved by the decoration function and this +approach needs to be extended to other properties if needed. Also, this sketch only passes +``kwargs`` to the permission function. + + diff --git a/docs/configuration.rst b/docs/configuration.rst index e9f79070..a10346a1 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -57,3 +57,19 @@ View decoration Each view delegated through to ``plotly_dash`` can be wrapped using a view decoration function. This enables access to be restricted to logged-in users, or using a desired conditions based on the user and session state. + +To restrict all access to logged-in users, use the ``login_required`` wrapper: + +.. code-block:: python + + PLOTLY_DASH = { + + ... + # Name of view wrapping function + "view_decorator": "django_plotly_dash.access.login_required", + ... + } + +More information can be found in the :ref:`view decoration ` section. + + diff --git a/docs/faq.rst b/docs/faq.rst index 2d386ecb..c6afa2f3 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -30,5 +30,5 @@ in this github `issue Date: Wed, 26 Dec 2018 09:55:04 -0800 Subject: [PATCH 2/2] Tidy up code based on linter comments --- django_plotly_dash/access.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/django_plotly_dash/access.py b/django_plotly_dash/access.py index 5d036d1e..6e101496 100644 --- a/django_plotly_dash/access.py +++ b/django_plotly_dash/access.py @@ -27,6 +27,8 @@ from django.contrib.auth.decorators import login_required as login_required_decorator +#pylint: disable=bare-except, unused-argument + def login_required(view_function, **kwargs): 'Wrap all DPD calls with login_required' return login_required_decorator(view_function) @@ -37,7 +39,7 @@ def login_required(view_function, **kwargs): dash_view_decorator = locals()[dash_view_decorator_name] except: mod_name, func_name = dash_view_decorator_name.rsplit('.', 1) - if len(mod_name): + if mod_name: mod = importlib.import_module(mod_name) dash_view_decorator = getattr(mod, func_name) else: