Skip to content

Commit 2b32149

Browse files
author
Jeff Balogh
committed
adding an @anonymous_csrf_exempt decorator
1 parent 767da8f commit 2b32149

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

README.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ token in the cache. It can be controlled through these settings:
7777
Default: ``60 * 60 * 2 # 2 hours``
7878

7979

80+
If you only want a view to have CSRF protection for logged-in users, you can
81+
use the ``anonymous_csrf_exempt`` decorator. This could be useful if the
82+
anonymous view is protected through a CAPTCHA, for example.
83+
84+
::
85+
86+
from session_csrf import anonymous_csrf_exempt
87+
88+
@anonymous_csrf_exempt
89+
def protected_in_another_way(request):
90+
...
91+
92+
8093
Why do I want this?
8194
-------------------
8295

session_csrf/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ def process_view(self, request, view_func, args, kwargs):
5858
if getattr(view_func, 'csrf_exempt', False):
5959
return
6060

61+
if (getattr(view_func, 'anonymous_csrf_exempt', False)
62+
and not request.user.is_authenticated()):
63+
return
64+
6165
# Bail if this isn't a POST.
6266
if request.method != 'POST':
6367
return self._accept(request)
@@ -110,6 +114,12 @@ def wrapper(request, *args, **kw):
110114
return wrapper
111115

112116

117+
def anonymous_csrf_exempt(f):
118+
"""Like @csrf_exempt but only for anonymous requests."""
119+
f.anonymous_csrf_exempt = True
120+
return f
121+
122+
113123
# Replace Django's middleware with our own.
114124
def monkeypatch():
115125
from django.views.decorators import csrf as csrf_dec

session_csrf/tests.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414

1515
import mock
1616

17-
from session_csrf import CsrfMiddleware, anonymous_csrf
17+
from session_csrf import CsrfMiddleware, anonymous_csrf, anonymous_csrf_exempt
1818

1919

2020
urlpatterns = patterns('',
2121
('^$', lambda r: http.HttpResponse()),
2222
('^anon$', anonymous_csrf(lambda r: http.HttpResponse())),
23+
('^no-anon-csrf$', anonymous_csrf_exempt(lambda r: http.HttpResponse())),
2324
('^logout$', anonymous_csrf(lambda r: logout(r) or http.HttpResponse())),
2425
)
2526

@@ -226,6 +227,14 @@ def test_existing_anon_cookie_not_in_cache(self):
226227
response = self.client.get('/anon')
227228
self.assertEqual(len(response._request.csrf_token), 32)
228229

230+
def test_anonymous_csrf_exempt(self):
231+
response = self.client.post('/no-anon-csrf')
232+
self.assertEqual(response.status_code, 200)
233+
234+
self.login()
235+
response = self.client.post('/no-anon-csrf')
236+
self.assertEqual(response.status_code, 403)
237+
229238

230239
class ClientHandler(django.test.client.ClientHandler):
231240
"""

0 commit comments

Comments
 (0)