Codeigniter 4 在 AJAX 模式中重用 CSRF 令牌

问题描述 投票:0回答:2

场景:

我正在开发 CMS 系统,我想向对象(页面、帖子、媒体等)添加一些类别。在我看来,为了保存新类别,我使用放置在 Bootstrap 模式中的 HTML 表单,该表单通过 AJAX 发送到我的控制器。全站启用CSRF保护。

第一次发送数据时,我通过表单传递 CSRF 令牌名称和哈希值。一旦被控制器中的 PHP 代码处理,我想在响应中传递 CSRF 值,这样我就能够在模式中“重用”表单(例如显示错误消息或/并创建另一个类别)。

但是,我无法访问

get_csrf_token_name()
get_csrf_hash()
方法将值传递回视图。

在我看来,adminmin/category/create.php:

...
<!-- CREATE CATEGORY MODAL MODAL -->
    <div class="modal" id="createCategory" tabindex="-1">
        <div class="modal-dialog modal-sm">
            <div class="modal-content">

                <div class="modal-header">
                    <h5 class="modal-title">Nová kategorie</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"></button>
                </div>

                <div class="modal-body">  
                    <form action="" method="post" id="createCategoryForm">
                        <input type="hidden" value="<?= csrf_hash(); ?>" name="<?= csrf_token(); ?>" id="csrf">

                        <div class="form-group mb-3">
                            <label for="title" class="form-label">Název kategorie</label>
                            <input type="text" class="form-control" name="title" id="title" value="">
                        </div>   
                </div>

                <div class="modal-footer">
                        <button type="submit" class="btn btn-primary" id="createCategoryConfirm">Vytvořit novou kategorii</button>
                    </form>
                </div>


            </div>
        </div>
    </div>

...

<script>
    $('#head').on('click', '.create', function() {

        $('#createCategory').modal('show');
        $('#createCategoryForm').attr('action', '<?= base_url(); ?>/admin/category/create');

        $('#createCategoryConfirm').click(function(e) {            
            e.preventDefault();         
           
            var url = $('#createCategoryForm').attr('action');
            var csrfElement = $('#csrf');
            var csrfName = csrfElement.attr('name');
            var csrfHash = csrfElement.attr('value');
            var categoryTitle = $('input[name=title]').val();

            var data = {
                [csrfName]: csrfHash,
                'title': categoryTitle
            };
            
            console.log(data);

            $.ajax({
                type: 'ajax',
                method: 'POST',
                url: url,
                data: data,
                dataType: 'json',
                contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
                headers: {'X-Requested-With': 'XMLHttpRequest'},
                success: function(result) {
                    console.log(result); 

                },
                error: function(result) {
                    console.log(result); 
                },
            });
        });
    });
        
</script>

在我的控制器 Category.php 中:


<?php

namespace App\Controllers\Admin;

use App\Controllers\BaseController;
use App\Models\CategoryModel;
use CodeIgniter\I18n\Time;


class Category extends BaseController {

    protected $model;
    protected $validator;
    protected $security;

    public function __construct() { 
        $this->model = new CategoryModel();
        $this->validation =  \Config\Services::validation();
        $this->security =  \Config\Services::security();
        helper(['form', 'date', 'url']);
    }

...

    public function create() {
        $response = [];

        // This part of code returns error
        // 
        // $response['csrf'] = array(
        //     'name' => $this->security->get_csrf_token_name(),
        //     'hash' => $this->security->get_csrf_hash()
        // );

        $response['security'] = $this->security;
        
        if ($this->request->isAJAX()) {

            $newCategory = [
                'title' => $this->request->getVar('title'),
                'slug' => url_title($this->request->getVar('title')),
                'author' => session()->get('id'),
                'created_at' => Time::now('Europe/Prague')->toDateTimeString(),
                'updated_at' => Time::now('Europe/Prague')->toDateTimeString(),
                'parent' => '0'
            ];

            $this->validation->run($newCategory, 'categoryRules');

            if (!empty($this->validation->getErrors())) {
                $this->model->save($newCategory);   
                $response['errors'] = $this->validation->getErrors();
                echo json_encode($response);
            } else {
                $this->model->save($newCategory);   
                $response['success'] = 'New category was created';
                echo json_encode($response);

            }
        }          
    }

...

在浏览器控制台中,AJAX 响应为

POST http://localhost/admin/category/create 500 (Internal Server Error)
,具有完整响应:

code: 500
file: "D:\Web\XAMPP\htdocs\lenka\app\Controllers\Admin\Category.php"
line: 38
message: "Call to undefined method CodeIgniter\Security\Security::get_csrf_token_name()"
title: "Error"

有人可以看到这里的问题吗?关于如何在 CI4 中重用 CSRF 令牌,有什么好的解决方案吗?我尝试将 CSRF regenerate 的配置值设置为 true 和 false,但没有效果。

php jquery ajax codeigniter codeigniter-4
2个回答
1
投票

更新.ENV中的这一行代码 应用程序/配置/安全

CSRF 重新生成 = false


0
投票

替代这个:

 var data = {
            [csrfName]: csrfHash,
            'title': categoryTitle
        };
        
        console.log(data);

        $.ajax({
            type: 'ajax',
            method: 'POST',
            url: url,
            data: data,
            dataType: 'json',
            contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
            headers: {'X-Requested-With': 'XMLHttpRequest'},
            success: function(result) {
                console.log(result); 

            },
            error: function(result) {
                console.log(result); 
            },
        });

为此:

 var data = {
            'title': categoryTitle
        };

        $.ajax({
            type: 'ajax',
            method: 'POST',
            url: url,
            data: {
                [csrfName]: csrfHash,
                data
            },
            dataType: 'json',
            contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
            headers: {'X-Requested-With': 'XMLHttpRequest'},
            success: function(result) {
                console.log(result); 

            },
            error: function(result) {
                console.log(result); 
            },
        });
© www.soinside.com 2019 - 2024. All rights reserved.