如何在Django REST Framework中实现服务端用户会话维护?
Absolutely! Using server-side sessions instead of storing OAuth access tokens in client-side local storage is a fantastic way to tighten up your security. The key win here is that sensitive authentication data never leaves the server (only a session ID does, which is far harder to exploit if configured correctly). Let’s walk through exactly how to implement this in Django REST Framework (DRF):
First, make sure Django's built-in session and auth systems are active—they're required for DRF's session authentication to work. Check your settings.py:
# settings.py INSTALLED_APPS = [ # ... your other apps 'django.contrib.sessions', 'django.contrib.auth', ] MIDDLEWARE = [ # ... other middleware 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', ]
These are enabled by default in most Django projects, but it’s worth double-checking.
Next, tell DRF to prioritize session authentication. You can set this globally in settings.py, or per-view if you need to mix authentication methods:
Global Configuration
# settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', # Keep other auth classes (like BasicAuth) only if you need them ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] }
Per-View Configuration
If you only want session auth for specific views:
from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView class ProtectedDataView(APIView): authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated] def get(self, request): return Response({'user_id': request.user.id, 'email': request.user.email})
Instead of issuing an access token, you’ll create a session when the user logs in, and destroy it when they log out. Here’s how to build those endpoints:
from rest_framework import status from rest_framework.response import Response from rest_framework.views import APIView from django.contrib.auth import authenticate, login, logout class LoginView(APIView): # Allow unauthenticated users to access this endpoint permission_classes = [] def post(self, request): username = request.data.get('username') password = request.data.get('password') # Authenticate the user against Django's auth system user = authenticate(request, username=username, password=password) if user is not None: # Create a session for the user login(request, user) return Response( {'message': 'Login successful', 'user': user.username}, status=status.HTTP_200_OK ) else: return Response( {'error': 'Invalid username or password'}, status=status.HTTP_401_UNAUTHORIZED ) class LogoutView(APIView): def post(self, request): # Destroy the user's session logout(request) return Response( {'message': 'Logout successful'}, status=status.HTTP_200_OK )
Don’t forget to wire these up in your urls.py:
from django.urls import path from .views import LoginView, LogoutView, ProtectedDataView urlpatterns = [ path('auth/login/', LoginView.as_view()), path('auth/logout/', LogoutView.as_view()), path('api/protected/', ProtectedDataView.as_view()), ]
To make sure your session setup is actually secure, tweak these settings in settings.py (especially for production):
# settings.py # Only send session cookies over HTTPS SESSION_COOKIE_SECURE = True # Prevent client-side JS from accessing the session cookie (blocks XSS theft) SESSION_COOKIE_HTTPONLY = True # Restrict cookie to same-site requests (blocks CSRF attacks) SESSION_COOKIE_SAMESITE = 'Strict' # Set session expiry time (adjust based on your needs) SESSION_COOKIE_AGE = 3600 # 1 hour # Refresh session expiry on every request SESSION_SAVE_EVERY_REQUEST = True
CSRF Protection Note
DRF’s SessionAuthentication requires CSRF protection for non-GET requests. Your frontend will need to include the CSRF token in the request header. Most frontend frameworks can handle this automatically, but here’s a quick JS snippet for vanilla setups:
// Extract CSRF token from cookie function getCsrfToken() { let token = null; const cookies = document.cookie.split(';'); for (const cookie of cookies) { const [name, value] = cookie.trim().split('='); if (name === 'csrftoken') { token = decodeURIComponent(value); break; } } return token; } // Include token in requests (example with fetch) fetch('/api/protected/', { method: 'POST', headers: { 'X-CSRFToken': getCsrfToken(), 'Content-Type': 'application/json' }, body: JSON.stringify({ data: 'example' }) });
- Security vs. Statelessness: Sessions require server-side storage (Django uses the database by default; for scalability, you can switch to Redis). OAuth tokens (like JWT) are stateless, but storing them client-side exposes you to XSS risks.
- Browser Convenience: Browsers automatically send session cookies with every request, so your frontend doesn’t need to manually attach an auth header. With tokens, you’d have to store and send them explicitly.
- Revocation: Revoking a session is easy—just delete it from the server. Revoking a JWT token is harder unless you use a token blacklist.
内容的提问来源于stack exchange,提问作者Moorani

