Я использую
- Spring Framework 4.0.0 RELEASE (GA)
- Spring Безопасность 3.2.0 RELEASE (GA)
- Struts 2.3.16
В котором я использую встроенный токен безопасности для защиты от атак CSRF.
<s:form namespace="/admin_side"
action="Category"
enctype="multipart/form-data"
method="POST"
validate="true"
id="dataForm"
name="dataForm">
<s:hidden name="%{#attr._csrf.parameterName}"
value="%{#attr._csrf.token}"/>
</s:form>
Это многостраничный запрос, в котором токен CSRF недоступен для безопасности Spring, если MultipartFilter
вместе с MultipartResolver
не настроен правильно, так что многопроцессорный запрос обрабатывается Spring.
MultipartFilter
в web.xml
конфигурируется следующим образом.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<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>
<filter>
<filter-name>AdminLoginNocacheFilter</filter-name>
<filter-class>filter.AdminLoginNocacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AdminLoginNocacheFilter</filter-name>
<url-pattern>/admin_login/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>NoCacheFilter</filter-name>
<filter-class>filter.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>/admin_side/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<description>Description</description>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>struts.devMode</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
И в applicationContext.xml
, MultipartResolver
регистрируется следующим образом.
<bean id="filterMultipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="-1" />
</bean>
Теперь токен CSRF получен с помощью Spring безопасности, но при этом возникает проблема в Struts.
Загруженные файлы теперь null
в классах действий Struts, как показано ниже.
@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value="struts-default")
public final class CategoryAction extends ActionSupport implements Serializable, ValidationAware, ModelDriven<Category>
{
private File fileUpload;
private String fileUploadContentType;
private String fileUploadFileName;
private static final long serialVersionUID = 1L;
//Getters and setters.
//Necessary validators as required.
@Action(value = "AddCategory",
results = {
@Result(name=ActionSupport.SUCCESS, type="redirectAction", params={"namespace", "/admin_side", "actionName", "Category"}),
@Result(name = ActionSupport.INPUT, location = "Category.jsp")},
interceptorRefs={
@InterceptorRef(value="defaultStack", "validation.validateAnnotatedMethodOnly", "true"})
})
public String insert(){
//fileUpload, fileUploadContentType and fileUploadFileName are null here after the form is submitted.
return ActionSupport.SUCCESS;
}
@Action(value = "Category",
results = {
@Result(name=ActionSupport.SUCCESS, location="Category.jsp"),
@Result(name = ActionSupport.INPUT, location = "Category.jsp")},
interceptorRefs={
@InterceptorRef(value="defaultStack", params={ "validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
public String load() throws Exception{
//This method is just required to return an initial view on page load.
return ActionSupport.SUCCESS;
}
}
Это происходит потому, что, по моему мнению, многопользовательский запрос уже обрабатывается и потребляется Spring, следовательно, он недоступен для Struts в качестве многостраничного запроса, и поэтому файловый объект в Struts класс действия null
.
Есть ли способ обойти эту ситуацию? В противном случае, теперь я оставил единственную возможность добавить токен к URL-адресу в качестве параметра строки запроса, который сильно обескуражен и не рекомендуется вообще.
<s:form namespace="/admin_side"
action="Category?%{#attr._csrf.parameterName}=%{#attr._csrf.token}"
enctype="multipart/form-data"
method="POST"
validate="true"
id="dataForm"
name="dataForm">
...
<s:form>
Короче говоря: Как получить файлы в классе действий Struts, если Spring создан для обработки запроса мульпарта? С другой стороны, если Spring не, сделанный для обработки множественного запроса, то он оденет маркер безопасности. Как преодолеть эту ситуацию?