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

UnityWebRequest对接Django时CSRF令牌缺失或错误问题求助

解决UnityWebRequest对接Django后端的CSRF令牌验证失败问题

我之前在Unity对接Django登录接口时也碰到过一模一样的问题,咱们从几个关键节点来排查和修正:

1. 表单提交格式不匹配(最可能的根源)

你当前用List<IMultipartFormSection>构建表单数据,这会让Unity发送multipart/form-data类型的请求,但Django默认的登录视图期望接收的是application/x-www-form-urlencoded格式的表单数据。这种格式不匹配会导致Django无法正确解析表单中的csrfmiddlewaretoken字段,直接触发CSRF验证失败。

修正方式:改用WWWForm来构建表单数据,Unity会自动设置正确的Content-Type头:

// 替换原来的List<IMultipartFormSection>
WWWForm formData = new WWWForm();
formData.AddField("username", "fake");
formData.AddField("password", "notpass");
formData.AddField("csrfmiddlewaretoken", csrfMiddlewareToken);

UnityWebRequest doLogin = UnityWebRequest.Post("https://dividedsky.herokuapp.com/accounts/login/", formData);

2. Cookie传递不完整

你的代码只提取了csrftoken,但Django返回登录页时可能还设置了其他Cookie(比如sessionid),这些Cookie需要在POST请求中完整传递。另外直接用SetRequestHeader("cookie", ...)会覆盖原有Cookie,建议先提取完整的Cookie键值对再设置:

修正Cookie提取和设置逻辑:

// 获取完整的Set-Cookie字符串
string fullSetCookie = loginPage.GetResponseHeader("set-cookie");
// 提取所有key=value格式的Cookie内容
Regex rxAllCookies = new Regex(@"([^=]+=[^;]+);");
MatchCollection cookieMatches = rxAllCookies.Matches(fullSetCookie);
StringBuilder cookieHeader = new StringBuilder();
foreach (Match match in cookieMatches)
{
    if (cookieHeader.Length > 0)
        cookieHeader.Append("; ");
    cookieHeader.Append(match.Groups[1].Value);
}

// 设置完整的Cookie请求头
doLogin.SetRequestHeader("cookie", cookieHeader.ToString());

3. 补充X-CSRFToken请求头(备选方案)

如果表单方式还是不行,可以尝试用Django支持的X-CSRFToken请求头传递令牌,这种方式有时候比表单字段更可靠:

// 从Cookie中提取csrftoken的值,添加到请求头
string csrfToken = cookieHeader.ToString().Split(';')[0].Split('=')[1];
doLogin.SetRequestHeader("X-CSRFToken", csrfToken);

4. 确保Referer头的正确性

你的代码已经设置了Referer头,但要确保它和登录页URL完全一致(包括协议、域名、路径),Django的CSRF验证会严格检查Referer是否属于可信域。

修改后的完整代码示例

UnityWebRequest loginPage = UnityWebRequest.Get("https://dividedsky.herokuapp.com/accounts/login/");
yield return loginPage.SendWebRequest();

if(loginPage.isNetworkError || loginPage.isHttpError)
{
    Debug.Log(loginPage.error);
    yield break;
}

// 提取完整的Cookie内容
string fullSetCookie = loginPage.GetResponseHeader("set-cookie");
Regex rxAllCookies = new Regex(@"([^=]+=[^;]+);");
MatchCollection cookieMatches = rxAllCookies.Matches(fullSetCookie);
StringBuilder cookieHeader = new StringBuilder();
foreach (Match match in cookieMatches)
{
    if (cookieHeader.Length > 0)
        cookieHeader.Append("; ");
    cookieHeader.Append(match.Groups[1].Value);
}

// 提取页面中的csrfmiddlewaretoken
string loginPageHtml = loginPage.downloadHandler.text;
Regex rxMiddleware = new Regex("name='csrfmiddlewaretoken' value='(?<csrf_token>.{64})'");
MatchCollection middlewareMatches = rxMiddleware.Matches(loginPageHtml);
string csrfMiddlewareToken = middlewareMatches[0].Groups["csrf_token"].Value;

// 构建正确格式的表单数据
WWWForm formData = new WWWForm();
formData.AddField("username", "fake");
formData.AddField("password", "notpass");
formData.AddField("csrfmiddlewaretoken", csrfMiddlewareToken);

// 发起登录请求
UnityWebRequest doLogin = UnityWebRequest.Post("https://dividedsky.herokuapp.com/accounts/login/", formData);
doLogin.SetRequestHeader("referer", "https://dividedsky.herokuapp.com/accounts/login/");
doLogin.SetRequestHeader("cookie", cookieHeader.ToString());
// 可选:添加X-CSRFToken头增强兼容性
string csrfToken = cookieHeader.ToString().Split(';')[0].Split('=')[1];
doLogin.SetRequestHeader("X-CSRFToken", csrfToken);

yield return doLogin.SendWebRequest();
Debug.Log(doLogin.downloadHandler.text);

额外注意点:

  • 确保你提取的csrfmiddlewaretoken和csrftoken Cookie值是匹配的(Django要求二者对应)
  • 如果你的Django后端配置了CSRF_TRUSTED_ORIGINS,要确保Unity请求的域名在这个列表内

内容的提问来源于stack exchange,提问作者Mark Miller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:24:27