csrf.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. from functools import wraps
  2. from asgiref.sync import iscoroutinefunction
  3. from django.middleware.csrf import CsrfViewMiddleware, get_token
  4. from django.utils.decorators import decorator_from_middleware
  5. csrf_protect = decorator_from_middleware(CsrfViewMiddleware)
  6. csrf_protect.__name__ = "csrf_protect"
  7. csrf_protect.__doc__ = """
  8. This decorator adds CSRF protection in exactly the same way as
  9. CsrfViewMiddleware, but it can be used on a per view basis. Using both, or
  10. using the decorator multiple times, is harmless and efficient.
  11. """
  12. class _EnsureCsrfToken(CsrfViewMiddleware):
  13. # Behave like CsrfViewMiddleware but don't reject requests or log warnings.
  14. def _reject(self, request, reason):
  15. return None
  16. requires_csrf_token = decorator_from_middleware(_EnsureCsrfToken)
  17. requires_csrf_token.__name__ = "requires_csrf_token"
  18. requires_csrf_token.__doc__ = """
  19. Use this decorator on views that need a correct csrf_token available to
  20. RequestContext, but without the CSRF protection that csrf_protect
  21. enforces.
  22. """
  23. class _EnsureCsrfCookie(CsrfViewMiddleware):
  24. def _reject(self, request, reason):
  25. return None
  26. def process_view(self, request, callback, callback_args, callback_kwargs):
  27. retval = super().process_view(request, callback, callback_args, callback_kwargs)
  28. # Force process_response to send the cookie
  29. get_token(request)
  30. return retval
  31. ensure_csrf_cookie = decorator_from_middleware(_EnsureCsrfCookie)
  32. ensure_csrf_cookie.__name__ = "ensure_csrf_cookie"
  33. ensure_csrf_cookie.__doc__ = """
  34. Use this decorator to ensure that a view sets a CSRF cookie, whether or not it
  35. uses the csrf_token template tag, or the CsrfViewMiddleware is used.
  36. """
  37. def csrf_exempt(view_func):
  38. """Mark a view function as being exempt from the CSRF view protection."""
  39. # view_func.csrf_exempt = True would also work, but decorators are nicer
  40. # if they don't have side effects, so return a new function.
  41. if iscoroutinefunction(view_func):
  42. async def _view_wrapper(request, *args, **kwargs):
  43. return await view_func(request, *args, **kwargs)
  44. else:
  45. def _view_wrapper(request, *args, **kwargs):
  46. return view_func(request, *args, **kwargs)
  47. _view_wrapper.csrf_exempt = True
  48. return wraps(view_func)(_view_wrapper)