Я столкнулся с проблемой при попытке проверить токен CSRF в моем приложении Symfony при использовании AJAX для удаления выбранных элементов. Вот обзор моей установки:
При попытке удалить выбранные элементы с помощью запроса AJAX я получаю сообщение об ошибке, указывающее, что токен CSRF недействителен, хотя я убедился, что токены совпадают между клиентом и сервером.
Код HTML-форма:
<tbody>
{% 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.info(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.info(selectedIds);
// Send AJAX request to delete selected rows
console.info($(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.info(response);
if (response.success) {
alert("success");
oTable.rows(".selected").fadeOut().remove().draw(false);
} else {
alert("Erreur");
}
},
error: function (xhr, status, error) {
console.info(error);
console.info(status);
console.info(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.info("Data sent:", data);
},
});
} else {
alert('Select a row!');
}
});
Что я пробовал Я несколько раз проверил, что имя поля CSRF в форме соответствует тому, которое я использую в своем запросе AJAX. Я использовал dump() в Symfony, чтобы убедиться, что токен CSRF правильно получен в контроллере.
Вопрос Почему, несмотря на все эти проверки, я продолжаю получать сообщение об ошибке недействительного токена CSRF? Есть ли что-то, что мне не хватает или на что следует обратить внимание?






Наконец, я понял, выполнив:
Контроллер:
$tokens = $request->get('_tokenannonce');
foreach ($annonces as $key => $annonce) {
$token = $tokens[$key];
.......
}
аякс-код:
// 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",
});
},
});
});