如何解决Django中CSRF“Forbidden Cookie未设置”错误?
Your problem boils down to cross-origin cookie restrictions and missing configuration on both the Django backend and Angular frontend. When your apps are hosted on the same server, the same-origin policy doesn’t block cookies, but cross-domain setups require explicit, targeted setup. Let’s walk through the fixes step by step:
1. Correct Django CORS & CSRF Settings
First, update your settings.py to properly handle cross-origin requests and secure cookies:
Update CORS Configurations
Since you’re using django-cors-headers, these settings are critical to allow cookies (credentials) across domains:
# Enable cross-origin credentials (required for cookies to be sent/received) CORS_ALLOW_CREDENTIALS = True # Whitelist your exact frontend origin (include protocol, IP, and port) CORS_ORIGIN_WHITELIST = [ "https://127.0.0.1:4200", "https://192.xxx.x.xx:7002" # Include backend's own origin for testing ] # Trust the frontend origin for CSRF validation CSRF_TRUSTED_ORIGINS = [ "127.0.0.1:4200", "192.xxx.x.xx:7002" ] # Ensure cookies are only sent over HTTPS (both apps use HTTPS, so this is safe) SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True # Remove any CSRF_COOKIE_DOMAIN setting if present (it blocks cross-domain cookies) # CSRF_COOKIE_DOMAIN = "your-domain.com" # Delete or comment this line
Add Custom Middleware for SameSite Cookie Attribute
Django 1.11 doesn’t natively support the SameSite cookie attribute, which is required for cross-domain cookies in modern browsers. Create a middleware to add this attribute to your CSRF cookie:
# Common/customMiddleware.py class ProcessCSRFCookie: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # Modify the CSRF cookie to allow cross-domain access if 'csrftoken' in response.cookies: csrf_cookie = response.cookies['csrftoken'] csrf_cookie['samesite'] = 'None' # Required for cross-domain csrf_cookie['secure'] = True # Must be paired with SameSite=None return response
Add this middleware to your MIDDLEWARE list after django.middleware.csrf.CsrfViewMiddleware:
MIDDLEWARE = [ 'Common.customMiddleware.ProcessRequest', 'django.middleware.security.SecurityMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'Common.customMiddleware.ProcessCSRFCookie', # Add here 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
2. Ensure Login View Triggers CSRF Cookie
Django’s CsrfViewMiddleware doesn’t automatically set the CSRF cookie for GET requests. In your login view, explicitly generate the CSRF token to trigger the cookie being sent:
from django.middleware.csrf import get_token def login_view(request): # Generate CSRF token to set the cookie in the response get_token(request) # Your existing login logic here return JsonResponse({"status": "success"})
3. Configure Angular to Send Credentials
Your Angular app needs to explicitly tell the browser to send cookies with cross-domain requests. You can do this globally with an interceptor or per-request:
Global Interceptor (Recommended)
Create an interceptor to add withCredentials: true to all HTTP requests:
// src/app/credentials.interceptor.ts import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable() export class CredentialsInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // Clone the request and enable credentials const modifiedRequest = request.clone({ withCredentials: true }); return next.handle(modifiedRequest); } }
Register the interceptor in your AppModule:
// src/app/app.module.ts import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { CredentialsInterceptor } from './credentials.interceptor'; @NgModule({ // ... other imports and declarations providers: [ { provide: HTTP_INTERCEPTORS, useClass: CredentialsInterceptor, multi: true } ] }) export class AppModule { }
Per-Request Alternative
If you prefer not to use an interceptor, add withCredentials: true to individual requests:
// Example login request this.http.get('https://192.xxx.x.xx:7002/login', { withCredentials: true }) .subscribe(response => { // Handle login success }); // Example POST request this.http.post('https://192.xxx.x.xx:7002/api/your-endpoint', yourData, { withCredentials: true }) .subscribe(response => { // Handle response });
Final Checks
- Clear your browser’s cache and cookies to ensure old, misconfigured cookies aren’t interfering.
- Verify in your browser’s dev tools (Application > Cookies) that the
csrftokencookie is being set for the backend domain. - Ensure both your Angular app (
ng server --ssl true) and Django API are running over HTTPS (required forSecurecookies).
内容的提问来源于stack exchange,提问作者Haroon Ahmed

