使用自定义 DELETE 方法时 Symfony 和 AJAX 的 CSRF 令牌验证问题

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

在使用 AJAX 删除所选项目时,我在 Symfony 应用程序中尝试验证 CSRF 令牌时遇到问题。以下是我的设置概述:

当尝试使用 AJAX 请求删除所选项目时,我收到一条错误,指示 CSRF 令牌无效,即使我已确保客户端和服务器之间的令牌匹配。

代码 HTML 表单:

                                        
                                        {% for annonce in allAnnonces %}
                                         
                                            <tr class="text-dark" id="annonce_ids{{ annonce.id }}">
                                                <td> 
                                                   
                                                    <input type="checkbox" name="ids" class="checkbox_ids" id="" value="{{ annonce.id }}">
                                                    <input type="hidden" name="_method" value="DELETE">
                                                    <input type="hidden" name="_tokenannonce" value="{{ csrf_token('annonce' ~ annonce.id) }}">
                                                    
                                                </td>
                                                <td>
                                                    {{ annonce.marques }} {{ annonce.modeles }} {{ annonce.year }}
                                                </td>
                                                <td>
                                                    {{ annonce.price | number_format(0, ',', ' ') }} {{ annonce.device }}
                                                </td>
........

                                                <td>
                                                    <a title="Éditer l'annonce" class="jsvm_cm-actn-btn p-1" href="{{ path('app_compte_annonceur_edit',{'id': annonce.id })}}">
                                                        <img src="{{ asset('/images/annonces/edit-icon.png')}}" alt="Modifier l'annonce" title="Éditer l'annonce">
                                                    </a>
                                                    
                                                    <form method="POST" action="{{ path('app_compte_annonceur_delete', {id: annonce.id}) }}" style="display: inline-block" onsubmit="return confirm('Êtes vous vraiment sûr ?')">
                                                        <input type="hidden" name="_method" value="DELETE">
                                                        <input type="hidden" name="_token" value="{{ csrf_token('delete' ~ annonce.id) }}">
                                                        <button class="btn" title="supprimer" type="submit">
                                                            <img src="{{ asset('/images/annonces/delete.png')}}" alt="Supprimer l'annonce" title="Supprimer l'annonce">
                                                        </button>
                                                    </form>
                                                </td>
                                            </tr>
                                        {% endfor %}
                                    </tbody>
<button class="jsvm_cm-pro-dashb-myveh-btn jsvm_cm-dlt-btn jsvm_multioperation-frontend border btn btn-danger p-2 button red"
                              
                                                data-for="removemulti"
                                                data-formid="jsvehiclemanager-list-form"
                                                id="delete-selected-btn"
                                                type="submit"
                                                data-delete-url="{{ path('app_delete_selected') }}">
                                                <img src="{{ asset('/images/annonces/delete.png')}}"
                                                    
                                                    <font style="vertical-align: inherit;">
                                                        <font style="vertical-align: inherit;">
                                                            delete selected row</font>
                                                    </font>
                                                </span>
                                            </button>

Symfony 控制器:

#[Route('/dashbord/Annonces/deleteselected', name: 'app_delete_selected', methods: 'DELETE')]
    public function deleteSelected(Request $request): JsonResponse
    {
        $message = [];
        
        $token = $request->get('_tokenannonce');
        $ids= $request->get('ids');
        // dump($data);
        dump($ids);
        dump($token);
        if (!empty($ids)) {
            
            $annonces = $this->annonceRepository->findBy(['id' => $ids]);
            dump($annonces);
            foreach ($annonces as $annonce) {
                
                dump($annonce->getId());
                // dump($this->->getToken('csrf_token')->getValue());
                dump($this->isCsrfTokenValid('annonce'.$annonce->getId(), $token));
                if ($this->isCsrfTokenValid('annonce'.$annonce->getId(), $token)) {
                    $this->em->remove($annonce);
                    $this->em->flush();
                    $this->addFlash('success', 'success');
                    $message = ['success' => true, 'message' => 'Success'];
                } else {
                    $this->addFlash('error', 'Invalid token');
                    $message = ['success' =>false, 'message' => 'Invalid token'];
                }
            }
        dump($message);
        return new JsonResponse(['message' => $message]);
    }

JavaScript AJAX 脚本:

// Handle multiple selection and row removal
$('#delete-selected-btn').click(function () {
    //var selectedRows = oTable.rows('.selected').data();
    var selectedRows = oTable.rows(".selected").nodes();
    var csrfToken = $('input[name="_tokenannonce"]').val();
    console.log(csrfToken);
    if (selectedRows.length > 0) {
        // Extract IDs from selected rows
       // var selectedIds = selectedRows.toArray().map(row => row[0]); // Assuming the ID is in the first column
        var selectedIds = []; 
         $(selectedRows).each(function () {
           var id = $(this).find("td:first-child input").val(); 
           selectedIds.push(id);
         });
        console.log(selectedIds);
         
        // Send AJAX request to delete selected rows
        console.log($(this).data('delete-url'));
        $.ajax({
          url: $(this).data("delete-url"),
          type: "DELETE",
          dataType: "json",
          processData: true,
          data: {
            ids: selectedIds,
           _tokenannonce: csrfToken
          },
          headers: {
            "_tokenannonce": csrfToken, // Include the CSRF token in the request headers
          },
          traditional: true,
          success: function (response) {
            console.log(response);
            if (response.success) {
              alert("success");
              oTable.rows(".selected").fadeOut().remove().draw(false);
            } else {
              alert("Erreur");
            }
          },
          error: function (xhr, status, error) {
            console.log(error);
            console.log(status);
            console.log(xhr);
            // alert('Erreur lors de la requête Ajax');
          },
          beforeSend: function (data) {
            $(selectedRows).css({
              "background-color": "#ccc",
              color: "#fff", // Change the text color for better visibility
            });
            console.log("Data sent:", data); 
          },
        });
    } else {
        alert('Select a row!');
    }
});

我尝试过的 我已经多次仔细检查表单中的 CSRF 字段名称是否与我在 AJAX 请求中使用的字段名称相匹配。 我在 Symfony 中使用 dump() 来验证 CSRF 令牌是否在控制器中正确检索。

问题 尽管进行了所有这些检查,为什么我仍然收到无效的 CSRF 令牌错误?有什么我遗漏或应该调查的吗?

php jquery ajax symfony csrf-token
1个回答
0
投票

最后我通过这样做弄清楚了:

控制器:

$tokens = $request->get('_tokenannonce');
foreach ($annonces as $key => $annonce) {
    $token = $tokens[$key];
    .......
}

ajax代码:

// Toggle the selected class on row click
oTable.on('click', 'tbody tr', function () {
    $(this).toggleClass('selected');
});

// Handle multiple selection and row removal
$("#delete-selected-btn").click(function () {

  var selectedRows = oTable.rows(".selected").nodes();
  var selectedIds = $(selectedRows)
    .map(function () {
      return $(this).find("td:first-child input").val();
    })
    .get();
  var tokens = $(selectedRows)
    .map(function () {
      return $(this).find("td:first-child input[name='_tokenannonce']").val();
    })
    .get();

  if (selectedIds.length > 0) {
    $.ajax({
      url: $(this).data("delete-url"),
      type: "DELETE",
      dataType: "json",
      data: {
        ids: selectedIds,
        _tokenannonce: tokens,
      },
      success: function (response) {
        if (response.success) {
          //alert(response.message);
          oTable.rows(".selected").remove().draw(false);
        } else {
          alert(response.message);
        }
      },
      fail: function (xhr, status, error) {
        alert("Error AJAX : " + status + " - " + error);
      },
      beforeSend: function () {
        $(selectedRows).css({
          "background-color": "#ccc",
          color: "#fff",
        });
      },
    });
  
});
© www.soinside.com 2019 - 2024. All rights reserved.