本地向Django API发POST请求时出现CSRF令牌错误(Angular2)
这个错误的核心原因是Django的CSRF保护机制在起作用:所有非GET的请求(比如POST)必须携带有效的CSRF token,你的Angular请求只设置了Content-Type,缺少这个关键的token,所以被拒绝了。
下面分两步来解决问题:
一、Django端配置检查与调整
首先确保你的Django项目已经正确启用了CSRF相关的组件,并且处理好跨域(如果Angular和Django运行在不同端口的话):
确认CSRF中间件和Session组件启用
在settings.py里,确保INSTALLED_APPS包含django.contrib.sessions,MIDDLEWARE列表里有以下两个中间件(顺序不能错):MIDDLEWARE = [ # ... 其他中间件 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', # ... 其他中间件 ]处理跨域请求(如果Angular和Django不在同一端口)
如果你的Angular运行在localhost:4200,Django在127.0.0.1:8000,属于跨域场景,需要安装并配置django-cors-headers:- 安装:
pip install django-cors-headers - 在
INSTALLED_APPS里添加:'corsheaders' - 在
MIDDLEWARE里把corsheaders.middleware.CorsMiddleware放在django.middleware.common.CommonMiddleware之前:MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # ... 其他中间件 ] - 添加跨域配置:
CORS_ALLOW_CREDENTIALS = True # 允许携带cookie CORS_ORIGIN_WHITELIST = [ 'http://localhost:4200', # Angular的地址 ]
- 安装:
二、Angular2代码修改
Django默认会把CSRF token存在名为csrftoken的cookie里,Angular需要读取这个cookie并把它放到请求头的X-CSRFToken字段中。这里有两种推荐的实现方式:
方法一:使用Angular的HttpClientXsrfModule(推荐)
Angular提供了专门处理XSRF的模块,可以自动帮你读取cookie并添加请求头,配置起来很简单:
在
AppModule中导入并配置HttpClientXsrfModule:import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http'; @NgModule({ declarations: [/* 你的组件 */], imports: [ HttpClientModule, HttpClientXsrfModule.withOptions({ cookieName: 'csrftoken', // Django的CSRF cookie名称 headerName: 'X-CSRFToken', // Django要求的请求头名称 }), ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }简化你的login服务代码(Angular会自动处理token和Content-Type):
import { HttpClient } from '@angular/common/http'; import { map } from 'rxjs/operators'; // ... constructor(private http: HttpClient) { } public login(user: any) { return this.http.post("http://127.0.0.1:8000/auth_api/login/", user, { withCredentials: true }) .pipe(map((data: any) => data)); }注:
withCredentials: true是跨域场景下必须的,确保cookie能被正常携带。
方法二:手动读取cookie并设置请求头
如果不想用Angular的XSRF模块,可以手动实现cookie读取和请求头设置:
添加一个读取cookie的工具函数:
private getCookie(name: string): string { const ca = document.cookie.split(';'); for (let cookie of ca) { const trimmedCookie = cookie.trim(); if (trimmedCookie.startsWith(`${name}=`)) { return trimmedCookie.substring(name.length + 1); } } return ''; }修改login方法,添加CSRF token到请求头:
public login(user: any){ const body = JSON.stringify(user); const headers = new Headers(); headers.append('Content-Type', 'application/json'); headers.append('X-CSRFToken', this.getCookie('csrftoken')); // 添加CSRF token return this.http.post("http://127.0.0.1:8000/auth_api/login/", body, { headers: headers, withCredentials: true // 跨域时必须开启,携带cookie }) .map((data: Response) => data.json()) }
注意事项
- 不要用
@csrf_exempt装饰器绕过CSRF检查,这会带来严重的安全风险,只有在完全信任请求来源的情况下才考虑使用。 - 确保你的Angular和Django的域名/端口配置正确,跨域时
CORS_ORIGIN_WHITELIST要包含Angular的准确地址。
内容的提问来源于stack exchange,提问作者ccr0x

