You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular6+Django SPA开发遇403错误:CSRF令牌缺失或不正确

解决Angular 6 + Django SPA的CSRF 403错误问题

嘿,我碰到过类似Angular和Django跨CSRF验证的坑,结合你的情况,咱们一步步来排查解决:

1. 先理清Angular请求模块的冲突

你同时导入了HttpClientModule和HttpModule,但Angular 6里HttpModule已经被弃用,推荐用HttpClient发起请求。这两个模块的XSRF处理逻辑不一样,可能导致自动携带CSRF头失效。

解决方案:

  • 移除HttpModule的导入,只保留HttpClientModule
  • 确保你的服务里用的是HttpClient而非旧的Http来发请求

调整后的AppModule配置:

import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
// 移除HttpModule的导入
import .... 

@NgModule({
  declarations: [
    AppComponent,
    RegisterComponent,
    LoginComponent,
    AlertComponent,
    ProfileComponent,
    RegisterinvoiceComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    AppRoutingModule,
    HttpClientModule // 只保留这个
  ],
  providers: [
    { 
      provide: HttpClientXsrfModule.withOptions({
        cookieName: 'csrftoken',
        headerName: 'X-CSRFToken',
      })
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

2. 修正Django的CSRF Cookie分发逻辑

你把@method_decorator(ensure_csrf_cookie)加在了create(POST)方法上,但这个装饰器的作用是在响应里设置CSRF cookie,应该加在用户首先访问的GET接口上(比如登录页接口、专门的CSRF获取接口)。POST请求本身已经需要CSRF验证,这时候再设置cookie已经晚了。

解决方案:

  • 创建一个专门的GET视图来分发CSRF cookie,或者在登录/首页的GET接口上加上这个装饰器:
from django.views.decorators.csrf import ensure_csrf_cookie
from django.http import HttpResponse

@ensure_csrf_cookie
def get_csrf_token(request):
    return HttpResponse(status=204)
  • 确保Angular在发起POST请求前,先调用这个GET接口拿到CSRF cookie

3. 检查Django的CORS和CSRF信任配置

如果你的前端(比如localhost:4200)和后端(localhost:8000)是跨域的,必须正确配置CORS和CSRF信任:

步骤1:安装并配置django-cors-headers

pip install django-cors-headers

在settings.py里添加:

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
]

# 允许的前端域名
CORS_ALLOWED_ORIGINS = [
    "http://localhost:4200",
]

# 允许携带凭证(Cookie)
CORS_ALLOW_CREDENTIALS = True

# 信任的CSRF来源
CSRF_TRUSTED_ORIGINS = [
    "http://localhost:4200",
]

步骤2:调整CSRF Cookie的属性

本地开发时(HTTP环境),要确保CSRF Cookie的属性不会阻止浏览器发送:

# settings.py
CSRF_COOKIE_SECURE = False  # 本地HTTP环境设为False,生产HTTPS设为True
CSRF_COOKIE_SAMESITE = 'Lax'  # 跨域时可以设为'None'(但需要配合CSRF_COOKIE_SECURE=True)

4. 手动携带CSRF头作为兜底方案

如果自动携带还是不行,可以手动从Cookie中提取CSRF token,然后在请求头里设置:

首先创建一个服务来获取Cookie:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class CookieService {
  getCookie(name: string): string | null {
    const value = "; " + document.cookie;
    const parts = value.split("; " + name + "=");
    if (parts.length === 2) return parts.pop()?.split(";").shift() || null;
    return null;
  }
}

然后在发起POST请求时手动加头:

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { CookieService } from './cookie.service';

// ...
constructor(private http: HttpClient, private cookieService: CookieService) {}

submitInvoice(data: any) {
  const csrfToken = this.cookieService.getCookie('csrftoken');
  const headers = new HttpHeaders({
    'X-CSRFToken': csrfToken || '',
    'Content-Type': 'application/json'
  });

  return this.http.post('/api/invoices/', data, { headers, withCredentials: true });
}

最后验证几个关键点

  • 确认POST请求的请求头里确实包含X-CSRFToken字段,值和Cookie里的csrftoken一致
  • 确认Cookie的Domain属性和请求的域名匹配,没有跨域问题
  • 检查Django的settings.py里CSRF_COOKIE_NAME是不是csrftoken(默认是,如果你没改的话没问题)

内容的提问来源于stack exchange,提问作者Marcus Grass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:06:29