middleware.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. from urllib import parse
  2. from django.conf import settings
  3. from django.contrib.auth.middleware import RemoteUserMiddleware as RemoteUserMiddleware_
  4. from django.db import ProgrammingError
  5. from django.http import Http404, HttpResponseRedirect
  6. from django.urls import reverse
  7. from .views import server_error
  8. class LoginRequiredMiddleware(object):
  9. """
  10. If LOGIN_REQUIRED is True, redirect all non-authenticated users to the login page.
  11. """
  12. def __init__(self, get_response):
  13. self.get_response = get_response
  14. def __call__(self, request):
  15. if settings.LOGIN_REQUIRED and not request.user.is_authenticated:
  16. # Redirect unauthenticated requests to the login page. API requests are exempt from redirection as the API
  17. # performs its own authentication. Also metrics can be read without login.
  18. api_path = reverse('api-root')
  19. if not request.path_info.startswith((api_path, '/metrics')) and request.path_info != settings.LOGIN_URL:
  20. return HttpResponseRedirect(
  21. '{}?next={}'.format(
  22. settings.LOGIN_URL,
  23. parse.quote(request.get_full_path_info())
  24. )
  25. )
  26. return self.get_response(request)
  27. class RemoteUserMiddleware(RemoteUserMiddleware_):
  28. """
  29. Custom implementation of Django's RemoteUserMiddleware which allows for a user-configurable HTTP header name.
  30. """
  31. force_logout_if_no_header = False
  32. header = settings.REMOTE_AUTH_HEADER
  33. class APIVersionMiddleware(object):
  34. """
  35. If the request is for an API endpoint, include the API version as a response header.
  36. """
  37. def __init__(self, get_response):
  38. self.get_response = get_response
  39. def __call__(self, request):
  40. api_path = reverse('api-root')
  41. response = self.get_response(request)
  42. if request.path_info.startswith(api_path):
  43. response['API-Version'] = settings.REST_FRAMEWORK_VERSION
  44. return response
  45. class ExceptionHandlingMiddleware(object):
  46. """
  47. Intercept certain exceptions which are likely indicative of installation issues and provide helpful instructions
  48. to the user.
  49. """
  50. def __init__(self, get_response):
  51. self.get_response = get_response
  52. def __call__(self, request):
  53. return self.get_response(request)
  54. def process_exception(self, request, exception):
  55. # Don't catch exceptions when in debug mode
  56. if settings.DEBUG:
  57. return
  58. # Ignore Http404s (defer to Django's built-in 404 handling)
  59. if isinstance(exception, Http404):
  60. return
  61. # Determine the type of exception. If it's a common issue, return a custom error page with instructions.
  62. custom_template = None
  63. if isinstance(exception, ProgrammingError):
  64. custom_template = 'exceptions/programming_error.html'
  65. elif isinstance(exception, ImportError):
  66. custom_template = 'exceptions/import_error.html'
  67. elif isinstance(exception, PermissionError):
  68. custom_template = 'exceptions/permission_error.html'
  69. # Return a custom error message, or fall back to Django's default 500 error handling
  70. if custom_template:
  71. return server_error(request, template_name=custom_template)