Codeigniter CSRF安全下AngularJS 1.x的$http.post()报500错误求助
解决CodeIgniter CSRF下AngularJS 1.x $http.post 500错误的方案
看起来你遇到的问题是CodeIgniter的CSRF验证在AJAX请求时没通过,导致500错误。普通表单能正常工作是因为CodeIgniter会自动为表单生成隐藏的CSRF令牌字段,而AngularJS的AJAX请求需要我们手动处理令牌传递,同时还要注意请求格式和后端的解析逻辑。
下面分步骤帮你解决:
第一步:确认CodeIgniter的CSRF配置
先打开application/config/config.php,找到这几个关键配置项,记好它们的值:
$config['csrf_protection'] = TRUE; $config['csrf_token_name'] = 'csrf_test_name'; // POST请求里需要携带的参数名 $config['csrf_cookie_name'] = 'csrf_cookie_name'; // 存储令牌的cookie名称
你的Angular代码里用的csrf_crypt大概率和csrf_token_name不一致,这是常见的错误点。
方案一:用表单编码格式提交(和普通表单一致)
这个方案最稳妥,因为和普通表单的请求格式完全相同,CodeIgniter能直接解析验证。
修改你的Angular代码:
- 注入
$httpParamSerializerJQLike(用来序列化表单数据) - 正确获取CSRF令牌的名称和值
- 调整
$http请求的配置
var angCntrl = angular.module('stepsReg',['ngMaterial', 'ngMessages', 'material.svgAssetsCache','mdPickers','naif.base64','ngFileUpload','uiCropper','ngCookies']) // 注入$httpParamSerializerJQLike用于表单数据序列化 angCntrl.controller('DemoCtrl', function($scope,$window, $cookies,$http,$httpParamSerializerJQLike,$mdpDatePicker,$mdpTimePicker,$timeout,$q,$mdDialog,$filter,Upload) { // 替换成你config里的csrf_token_name和csrf_cookie_name var csrfTokenName = 'csrf_test_name'; var csrfTokenValue = $cookies.get('csrf_cookie_name'); $scope.insertid = ''; $scope.outletid = ''; $scope.currentid = currentid; $scope.stepOneNext = function() { var insertid = $('#insertid').val(); var profileId = $('.current_id').val(); var pCategory = $('#parentCat').val(); var name = $('#name').val(); var email = $('#email').val(); // 构造请求数据,把CSRF令牌放在最前面 var postData = {}; postData[csrfTokenName] = csrfTokenValue; postData.insertid = insertid; postData.profileId = profileId; postData.pCategory = pCategory; postData.name = name; postData.email = email; $http({ method: 'post', url: base_url+'customer/steponeRegistion', // 序列化数据成表单格式 data: $httpParamSerializerJQLike(postData), // 设置正确的Content-Type headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).then(function (response) { alert(response.data); $scope.insertid = response.data; }).catch(function(error) { // 增加错误捕获,方便调试 console.error('请求出错:', error); alert('请求失败,请查看控制台日志'); }); } });
方案二:让CodeIgniter支持JSON格式的CSRF验证
如果你坚持用JSON格式提交数据,需要修改CodeIgniter的Security类,让它能从JSON请求体里读取CSRF令牌。
- 在
application/core目录下创建MY_Security.php文件,内容如下:
<?php class MY_Security extends CI_Security { protected function csrf_verify() { // 先执行默认的CSRF验证(处理表单编码的请求) if (parent::csrf_verify()) { return TRUE; } // 如果默认验证失败,尝试解析JSON请求体 $rawInput = file_get_contents('php://input'); $inputData = json_decode($rawInput, TRUE); // 检查JSON里是否包含正确的CSRF令牌 if (isset($inputData[$this->_csrf_token_name]) && $this->csrf_validate_token($inputData[$this->_csrf_token_name])) { $this->_csrf_set_hash(); // 更新CSRF令牌 return TRUE; } // 验证失败,返回错误 $this->csrf_show_error(); return FALSE; } }
- 然后修改你的Angular代码,确保CSRF令牌的参数名和CodeIgniter的
csrf_token_name一致,并且正确设置请求头:
var angCntrl = angular.module('stepsReg',['ngMaterial', 'ngMessages', 'material.svgAssetsCache','mdPickers','naif.base64','ngFileUpload','uiCropper','ngCookies']) angCntrl.controller('DemoCtrl', function($scope,$window, $cookies,$http,$mdpDatePicker,$mdpTimePicker,$timeout,$q,$mdDialog,$filter,Upload) { var csrfTokenName = 'csrf_test_name'; // 替换成你的config值 var csrfTokenValue = $cookies.get('csrf_cookie_name'); $scope.insertid = ''; $scope.outletid = ''; $scope.currentid = currentid; $scope.stepOneNext = function() { var insertid = $('#insertid').val(); var profileId = $('.current_id').val(); var pCategory = $('#parentCat').val(); var name = $('#name').val(); var email = $('#email').val(); $http({ method: 'post', url: base_url+'customer/steponeRegistion', data:{ [csrfTokenName]: csrfTokenValue, "insertid":insertid, "profileId":profileId, "pCategory":pCategory, "name":name, "email":email }, // 正确设置JSON请求头,之前的config写法错误 headers: {'Content-Type': 'application/json'} }).then(function (response) { alert(response.data); $scope.insertid = response.data; }).catch(function(error) { console.error('请求出错:', error); }); } });
额外调试建议
- 打开浏览器开发者工具(F12),查看Network标签里的请求,检查Request Headers和Form Data/Payload里是否包含正确的CSRF令牌。
- 查看CodeIgniter的日志文件(
application/logs/目录下),500错误通常会有详细的PHP错误信息,能帮你快速定位问题。 - 确保
base_url没有跨域问题,如果是跨域请求,还需要配置CORS并允许携带cookie。
内容的提问来源于stack exchange,提问作者Sherin Green
相关产品推荐
相关产品推荐

