Ознакомьтесь с официальной рекомендацией Spring Security: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-multipart
Есть два основных способа сделать это: (1) поместить MultipartFilter перед фильтром Spring Security и (2) включить маркер CSRF в действие формы, как вы это делаете. Первый вариант является рекомендуемым:
Первый вариант - убедиться, что указан MultipartFilter.
перед фильтром Spring Security. Указание MultipartFilter
перед фильтром Spring Security означает, что нет авторизации
для вызова MultipartFilter, что означает, что каждый может разместить
временные файлы на вашем сервере. Тем не менее, только авторизованные пользователи будут
возможность отправить файл, который обрабатывается вашим приложением. В
Вообще, это рекомендуемый подход, потому что временный файл
загрузка должна иметь незначительное влияние на большинство серверов.
Чтобы убедиться, что MultipartFilter указан перед фильтром Spring Security с конфигурацией Java, пользователи могут переопределить beforeSpringSecurityFilterChain, как показано ниже:
public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
}
Чтобы убедиться, что MultipartFilter указан перед фильтром Spring Security с конфигурацией XML, пользователи могут убедиться, что элемент MultipartFilter размещен перед springSecurityFilterChain в файле web.xml, как показано ниже:
<filter>
<filter-name>MultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Обратите внимание, что если вы все еще хотите использовать действие формы, параметры запроса могут быть пропущены. Попробуйте изменить "headerName" на "имя_параметра":
<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">
РЕДАКТИРОВАТЬ : Если вы не можете переключиться на контейнер на основе сервлета (например, Jetty или Tomcat), и рекомендация по действию формы не работает, существует недавний поток Stack Overflow обсуждает эту проблему.
Один из разработчиков сообщил, что может решить проблему с помощью AJAX:
Я решил эту проблему следующим образом:
- отправка файла из нескольких частей с использованием vanilla javascript, как в
Руководство Mozilla
- добавление токена _csrf в заголовок HTML в мета
теги, как в руководстве Spring для отправки токена CSRF с помощью Ajax
- вместо использования jquery, добавив его непосредственно к объекту XHR
var csrfToken = $("meta[name='_csrf']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
XHR.setRequestHeader(csrfHeader, csrfToken);
XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary);
XHR.send(data);
Тот же разработчик сообщил об этой проблеме в Spring , но пока не получил никакого внимания.