API-Token: Anfragen mit Bearer-Token brauchen kein CSRF-Token
Native Clients (diora desktop) haben kein CSRF-Cookie; ein Browser hängt den Authorization-Header nie von selbst an, daher ist das sicher. Nötig z. B. für den M3U-Import, der nicht csrf_exempt ist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
086ce29020
commit
77d662a9cb
2 changed files with 19 additions and 0 deletions
|
|
@ -22,4 +22,9 @@ class ApiTokenAuthMiddleware:
|
|||
api_token = ApiToken.objects.select_related('user').filter(token=token).first()
|
||||
if api_token is not None:
|
||||
request.user = api_token.user
|
||||
# Browsers never attach this header on their own, so a
|
||||
# token request can't be a cross-site forgery; native
|
||||
# clients have no CSRF cookie to send. (CsrfViewMiddleware
|
||||
# checks this flag in process_view, which runs after us.)
|
||||
request._dont_enforce_csrf_checks = True
|
||||
return self.get_response(request)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,20 @@ class ApiTokenAuthMiddlewareTests(TestCase):
|
|||
resp = self.client.get('/books/', HTTP_AUTHORIZATION=f'Bearer {self.token.token}')
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def test_bearer_token_needs_no_csrf_token(self):
|
||||
# import_m3u is not csrf_exempt: without a token it must still be protected.
|
||||
from django.test import Client
|
||||
client = Client(enforce_csrf_checks=True)
|
||||
m3u = '#EXTM3U\n#EXTINF:-1,Test FM\nhttps://example.com/stream\n'
|
||||
resp = client.post('/radio/import/', data=m3u, content_type='text/plain')
|
||||
self.assertIn(resp.status_code, (302, 401, 403))
|
||||
resp = client.post('/radio/import/', data=m3u, content_type='text/plain',
|
||||
HTTP_AUTHORIZATION=f'Bearer {self.token.token}')
|
||||
self.assertNotEqual(resp.status_code, 403)
|
||||
resp = client.post('/radio/import/', data=m3u, content_type='text/plain',
|
||||
HTTP_AUTHORIZATION='Bearer not-a-real-token')
|
||||
self.assertIn(resp.status_code, (302, 401, 403))
|
||||
|
||||
def test_regenerate_view_requires_login_and_rotates_token(self):
|
||||
resp = self.client.post('/accounts/api-token/regenerate/')
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue