CodeIgniter启用CSRF后AJAX POST提交报403 Forbidden问题
根据你提供的配置和代码,咱们一步步排查并解决这个问题:
1. 确认表单选择器与CSRF令牌的归属
你提到控制台显示表单已包含CSRF令牌隐藏输入,但要先确保这个隐藏输入确实在你选中的#formData表单内部。form_open()默认不会给表单添加id="formData"属性,所以需要你在生成表单时显式指定:
<?php echo form_open('login/verify', ['id' => 'formData']); ?>
如果表单id不匹配,new FormData($(this)[0])就无法捕获CSRF令牌字段,自然会触发CSRF验证失败导致403。
2. 修正AJAX请求的URL路径
你的AJAX请求URL写的是'example.com.sg/login/verify',这种写法容易被浏览器解析为相对路径(比如当前页面是example.com.sg/login,会被解析为example.com.sg/login/example.com.sg/login/verify),导致请求到错误地址,触发验证失败。
建议用CodeIgniter的base_url()生成正确的绝对路径:
url: '<?php echo base_url('login/verify'); ?>',
如果你的JS代码是单独的外部文件,可以先在HTML页面中定义全局变量:
<script>const baseUrl = '<?php echo base_url(); ?>';</script>
再在JS中调用:
url: baseUrl + 'login/verify',
3. 确保AJAX请求携带Cookie(同域场景)
CodeIgniter的CSRF验证需要POST数据中的令牌和Cookie中的令牌匹配。虽然同域下AJAX默认会携带Cookie,但有些场景下可能被浏览器限制,你可以显式配置强制携带:
$.ajax({ type: 'post', cache : false, processData: false, dataType: 'json', url: '<?php echo base_url('login/verify'); ?>', data: formData, // 添加这部分配置 xhrFields: { withCredentials: true }, success: function (res) { if(res.status == true){ window.location.href = res.redirect; } }, error: function(err){ console.log(err.responseText) } });
4. 验证请求中CSRF令牌的发送状态
打开浏览器开发者工具的Network标签,找到你的POST请求,查看Form Data部分是否包含csrf_token_name字段(对应你配置的$config['csrf_token_name']值)。如果没有,说明表单选择器错误或者令牌字段不在表单内,需要调整表单结构。
5. 排除其他干扰因素
- 确认
csrf_expire设置的7200秒(2小时)未过期,测试时可以临时设为更大的值(比如86400)验证; - 检查
csrf_exclude_uris是否误添加了当前URI(你的配置是空数组,这部分没问题); - 确保服务器端没有其他安全插件/模块(比如ModSecurity)拦截了POST请求。
按照上面的步骤排查,应该能解决AJAX POST 403的问题。
内容的提问来源于stack exchange,提问作者Leon

