React/TypeScript项目获取CSRFToken遇403错误,请求排查
我是React/TypeScript新手开发者,项目中使用Axios和Mobx实现授权功能,目前核心问题是无法获取预期的CSRFToken,请求时出现403错误(提示token不正确)。
浏览器客户端Cookie中看不到该token,但响应头里存在Cookie。后端基于Django开发,后端人员表示配置无误,我对后端代码理解有限,恳请帮忙排查问题。
相关代码
http.ts
import axios from 'axios'; export const API_URL = process.env.NEXT_PUBLIC_BASE_URL; const $api = axios.create({ withCredentials: true, baseURL: API_URL, xsrfHeaderName: "X-CSRFToken", xsrfCookieName: "csrftoken", }) export default $api;
store.ts
export default class Store { async sendCode(email: string) { try { const response = await AuthService.sendCode(email); console.log(response); sessionStorage.setItem('email', response.data.email); this.setAuth(false); this.setUser(response.data.user); } catch (e: any) { console.log(e.response?.data?.message); } } }
AuthService.ts
export default class AuthService { static async sendCode(email: string): Promise<AxiosResponse<AuthResponse>> { return $api( { method: 'post', url: '/auth/login/', data: email, headers: { 'X-CSRFToken': document.cookie.split('=')[1], 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json', } } ) } }
排查与解决方案
1. 移除手动设置的CSRF Token Header
你已经在Axios实例中配置了xsrfHeaderName和xsrfCookieName,Axios会自动从Cookie中读取csrftoken并添加到请求头X-CSRFToken中。但当前代码里手动通过document.cookie.split('=')[1]获取Token的方式非常脆弱——如果Cookie中有多个键值对,或者csrftoken不是第一个Cookie,就会拿到错误的值,直接导致403错误。
修改AuthService.ts,删除手动设置的X-CSRFToken头,并调整请求数据格式:
export default class AuthService { static async sendCode(email: string): Promise<AxiosResponse<AuthResponse>> { return $api( { method: 'post', url: '/auth/login/', data: { email }, // 改为对象格式,匹配后端JSON解析预期 headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json', } } ) } }
2. 确认Django后端CSRF相关配置
即使后端说配置无误,仍需核对以下关键项:
CSRF_COOKIE_SECURE:生产环境需设为True(启用HTTPS时),开发环境可设为FalseCSRF_COOKIE_HTTPONLY:建议设为False(虽然Axios不需要前端读取Cookie,但如果设为True,前端document.cookie确实看不到该值,但Axios仍能自动处理)CSRF_TRUSTED_ORIGINS:必须包含你的前端域名(例如http://localhost:3000)CORS_ALLOW_CREDENTIALS:设为True,允许跨域请求携带CookieCORS_ALLOWED_ORIGINS:包含前端域名
3. 确保请求前已获取CSRF Cookie
Django默认会在GET请求(如页面访问)时设置CSRF Cookie,但单页应用可能缺少这个触发步骤。可以在发送授权请求前,先发送一个GET请求到后端专门的CSRF端点(比如/csrf/,后端需配置该路由返回空响应并设置Cookie):
在AuthService.ts中添加获取CSRF的方法:
export default class AuthService { static async getCsrfToken() { await $api.get('/csrf/'); } static async sendCode(email: string): Promise<AxiosResponse<AuthResponse>> { // ... 之前的修改后代码 } }
然后在store.ts的sendCode方法中先调用该方法:
export default class Store { async sendCode(email: string) { try { await AuthService.getCsrfToken(); // 先获取CSRF Cookie const response = await AuthService.sendCode(email); console.log(response); sessionStorage.setItem('email', response.data.email); this.setAuth(false); this.setUser(response.data.user); } catch (e: any) { console.log(e.response?.data?.message); } } }
4. 验证Cookie是否被正确存储
修改完成后,打开浏览器开发者工具的Application > Cookies面板,确认csrftoken是否存在。如果仍然不存在,检查后端响应头中的Set-Cookie字段,看是否包含csrftoken,以及Cookie的Domain、Path等属性是否匹配前端域名。
内容的提问来源于stack exchange,提问作者shwedus

