Spring Security干扰转换/重定向/页面加载

时间:2016-03-17 14:53:11

标签: spring jsf spring-security spring-webflow-2

我有一个小的Spring / JSF / JDBC webapp,在添加Spring Security之前一直运行良好。自添加springsecurityfilterchain以来,登录/欢迎屏幕上的注册按钮(而不是登录)不再起作用。出现JSF primefaces加载栏,但无限期保留而不转换到下一页。 我的初步调查让我相信它与springsecurityfilterchain有关,因为评论这段代码基本上可以打开/关闭问题。

非常感谢任何帮助。

代码: 的web.xml

    <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>KimaPortal</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>Resources Servlet</servlet-name>
    <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Resources Servlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
  </servlet-mapping>
  <servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value></param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/app/*</url-pattern>
  </servlet-mapping>
  <filter>
    <filter-name>charEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>charEncodingFilter</filter-name>
    <url-pattern>*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
  <context-param>
    <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>
  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
  </context-param>
  <listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
  </listener>

  <!--  Spring security filters -->
  <filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>

  <filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>



</web-app>

应用context.xml中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<import resource="datasource-config.xml" />
<import resource="webflow-config.xml"/>
<import resource="security-config.xml"/>

<!-- <bean id="userEntity" class="org.bluprnt.KimaPortal.domain.UserEntity"/> -->
<bean id="userEntityServices" class="org.bluprnt.KimaPortal.domain.UserEntityServices">
    <property name="authenticationManager" ref="authenticationManager" />
</bean> 

<bean id="applicationContextProvider" class="org.bluprnt.KimaPortal.domain.ApplicationContextProvider"/>

</beans>

的Webflow-config.xml中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns:faces="http://www.springframework.org/schema/faces"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/webflow-config 
http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd 
http://www.springframework.org/schema/faces 
http://www.springframework.org/schema/faces/spring-faces.xsd">

<bean id="facesContextListener" class="org.springframework.faces.webflow.FlowFacesContextLifecycleListener">
</bean>

<!-- <bean id="jpaFlowExecutionListener" class="org.springframework.webflow.persistence.JpaFlowExecutionListener"> -->
<!-- <constructor-arg ref="entityManagerFactory" /> -->
<!-- <constructor-arg ref="transactionManager" /> -->
<!-- </bean> -->

<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="facesContextListener"/>
<webflow:listener ref="securityFlowExecutionListener" />
<!-- <webflow:listener ref="jpaFlowExecutionListener" /> -->
</webflow:flow-execution-listeners>
</webflow:flow-executor> 

<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices" base-path="WEB-INF/flows">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>

<faces:flow-builder-services id="facesFlowBuilderServices" development="true"/>

<faces:resources/>

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="1"/>
<property name="flowRegistry" ref="flowRegistry"/>
<property name="defaultHandler">
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
</property>
</bean>

<bean class="org.springframework.faces.webflow.JsfFlowHandlerAdapter">
<property name ="flowExecutor" ref="flowExecutor" />
</bean>

<bean id="faceletsViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.faces.mvc.JsfView" />
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".xhtml" />
</bean>

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

<bean id="securityFlowExecutionListener"
      class="org.springframework.webflow.security.SecurityFlowExecutionListener" />


</beans>

安全-config.xml中

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">

<security:http auto-config="true">
    <security:form-login login-page="/app/main"  default-target-url="/app/account" />
    <security:logout logout-url="/app/logout" logout-success-url="/app/main" />
</security:http>

<security:authentication-manager>
    <security:authentication-provider user-service-ref="userEntityServices">
        <security:password-encoder hash="md5"/>
    </security:authentication-provider>
</security:authentication-manager>

<bean id="userEntityAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <property name="userDetailsService" ref="userEntityServices" />
    <property name="hideUserNotFoundExceptions" value="false"/>
</bean>

<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <constructor-arg>
        <ref bean="daoAuthenticationProvider" />
    </constructor-arg>
</bean>   

<bean id="daoAuthenticationProvider"
    class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userEntityServices"/>
</bean>

</beans> 

主flow.xml

<?xml version="1.0" encoding="UTF-8"?>

<flow xmlns="http://www.springframework.org/schema/webflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow
        http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"> 

    <var name="user" class="org.bluprnt.KimaPortal.domain.UserEntity" />



    <view-state id="welcome" view="welcome.xhtml">
        <transition on="newUser" to="signUp"/>
    </view-state>

    <view-state id="signUp" view="signUp.xhtml" model="user">
        <transition on="backToSignIn" to="welcome"/>
        <transition on="confirmSignUp" to="authentication">
        <evaluate expression="userEntityServices.createUserEntity(user)" />
        </transition>
    </view-state>

    <action-state id="authentication">
        <evaluate expression="userEntityServices.authenticateUser(user)" />
        <transition on="yes" to="authenticationSuccessful" />
        <transition on="no" to="welcome" />
    </action-state>

    <end-state id="authenticationSuccessful" view="externalRedirect:account" />

</flow> 

帐户flow.xml

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow
        http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

<!-- use spring roles tables TO DO -->
<secured attributes="ROLE_USER"/>

    <view-state id="userHome" view="authenticatedWelcome.xhtml">
    </view-state>

</flow>

UserEntityServices.java

package org.bluprnt.KimaPortal.domain;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.*;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.DataSourceUtils;

public class UserEntityServices implements UserDetailsService {
    private ApplicationContext ctx;
    private DataSource ds;
    private Connection c;
    private AuthenticationManager authenticationManager;


    public void createUserEntity(UserEntity user) {
        try {
            // Check if user exists
            if (checkIfUserExists(user) == false){
                createDBConnectionIfNA();
                    // retrieve a list of three random cities
                String statement = new String("insert into kima_users " +
                "values ('" + user.getUserName() +"', '" 
                        + user.getPassword() + "', '" 
                        + user.getFirstName() + "', '" 
                        + user.getLastName() + "');");
                System.out.println(statement);
                PreparedStatement ps = c.prepareStatement(statement);
                ps.execute();

            } else {
                // throw error about user already existing
                // TO DO !!
            }
        } catch (SQLException ex) {
            // something has failed and we print a stack trace to analyze the error
            ex.printStackTrace();
            // ignore failure closing connection
                    try { c.close(); } catch (SQLException e) { }
        } finally {
            // properly release our connection
            DataSourceUtils.releaseConnection(c, ds);
            this.c = null;
            this.ds = null;
        }

    }

    public boolean checkIfUserExists (UserEntity user){
        try {
            createDBConnectionIfNA();
            // SQL statement to check whether username already exists in DB
            String statement = new String("select * from kima_users where userName = '" + user.getUserName() + "' ");
            System.out.println(statement);
            PreparedStatement ps = c.prepareStatement(statement);
            ResultSet rs = ps.executeQuery();
            if (!rs.next()){
                    //user does not exist
                    return false;
                }else{
                    //user exists
                    return true;
                }
        } catch (SQLException ex) {
            // something has failed and we print a stack trace to analyze the error
            ex.printStackTrace();
            // ignore failure closing connection
            try { c.close();} catch (SQLException e) { }
        } finally {
            // properly release our connection
            DataSourceUtils.releaseConnection(c, ds);
            this.c = null;
            this.ds = null;
        }
        //conservative guaranteed return value
        return true;
    }


    //method to retrieve userEntity from DB by user name
    public UserEntity getUserFromDBByUserName (String userName) {
        try {
            UserEntity user = new UserEntity();
            createDBConnectionIfNA();
            String statement = new String("select * from kima_users where userName = '" + userName + "' ");
            System.out.println(statement);
            PreparedStatement ps = c.prepareStatement(statement);
            ResultSet rs = ps.executeQuery();
            user.setUserName(rs.getString("userName"));
            user.setPassword(rs.getString("password"));
            user.setFirstName(rs.getString("firstName"));
            user.setLastName(rs.getString("lastName"));
            return user;
        } catch (SQLException ex) {
            // something has failed and we print a stack trace to analyse the error
            ex.printStackTrace();
            // ignore failure closing connection
            try { c.close();} catch (SQLException e) { }
        } finally {
            // properly release our connection
            DataSourceUtils.releaseConnection(c, ds);
            this.c = null;
            this.ds = null;
        }
        return null;
    }


    //method for user authentication as part of login procedure main-flow to account-flow
    public boolean authenticateUser (UserEntity user){
        System.out.println("2");
        try {
        Authentication request = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        //authenticationManager.authenticate calls loadUserByUsername(username)
        Authentication result =  authenticationManager.authenticate(request);
        SecurityContextHolder.getContext().setAuthentication(result);
        return true;
        } catch(AuthenticationException e){
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), "Sorry!"));
            return false;
        }
    }

    public AuthenticationManager getAuthenticationManager() {
        return authenticationManager;
    }

    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }


    //userDetailsService implementation for spring security
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        System.out.println("1");
        UserEntity user = getUserFromDBByUserName(userName);
        if (user == null){
            throw new UsernameNotFoundException(String.format("No such user with name '%s'", userName));
        }
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        User userDetails = new User(user.getUserName(), user.getPassword(), authorities);
        return userDetails;

    }

    // method to create DB connection and to pass on applicationContext, dataSource and Connection as instance variable
    // ATTENTION: dataSource and connection to be closed after query is execute
    private void createDBConnectionIfNA(){
        // check whether there is an existing connection - create one if not
        if (!(this.ctx != null && this.ds != null && this.c != null)) {
            // Create a new application context. this processes the Spring config
            ApplicationContextProvider acp = new ApplicationContextProvider();
            ApplicationContext ctx = acp.getApplicationContext();
            // Retrieve the data source from the application context
            DataSource ds = (DataSource) ctx.getBean("dataSource");
            // Open a database connection using Spring's DataSourceUtils
            java.sql.Connection c = DataSourceUtils.getConnection(ds);
            //pass on connection objects to instance variables
            this.ctx = ctx;
            this.ds = ds;
            this.c = c;
        }
    }

}

pom.xml包含以下依赖项(由于大小限制而被截断):

<org.springframework.version>4.2.4.RELEASE</org.springframework.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat-maven-plugin</artifactId>
      <version>2.2</version>
      <type>pom</type>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.1.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <type>maven-plugin</type>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.webflow</groupId>
        <artifactId>spring-faces</artifactId>
        <version>2.4.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-api</artifactId>
        <version>2.2.13</version>
    </dependency>
    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>5.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.sun.facelets</groupId>
        <artifactId>jsf-facelets</artifactId>
        <version>1.1.14</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-impl</artifactId>
        <version>2.2.13</version>
    </dependency>
    <dependency>
        <groupId>antlr</groupId>
        <artifactId>antlr</artifactId>
        <version>2.7.7</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>2.0.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.5.6</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>2.5</version>
        <type>pom</type>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.webflow</groupId>
        <artifactId>spring-webflow</artifactId>
        <version>2.4.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>
  </dependencies>

1 个答案:

答案 0 :(得分:0)

我们遇到了完全相同的问题。该问题源于Spring过滤器链。启用 spring-security 后,您在web.xml中添加了新的过滤器链组件,如下所示:

<filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

这会导致添加一组完整的过滤器。其中一个过滤器是为了防止CSRF (Cross-site Request Forgery)。不知何故, webflow-2 spring-security 的组合会导致CSRF令牌在处理链中丢失。当查看过滤器链在CsrfFilter中停止的相应日志部分时,这一点就变得明显了。

DEBUG 2016-07-25 06:47:59,013 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 1 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG 2016-07-25 06:47:59,013 (HttpSessionSecurityContextRepository.java:171) - HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG 2016-07-25 06:47:59,014 (HttpSessionSecurityContextRepository.java:101) - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@42281bdb. A new one will be created.
DEBUG 2016-07-25 06:47:59,014 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 2 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG 2016-07-25 06:47:59,014 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG 2016-07-25 06:47:59,014 (HstsHeaderWriter.java:128) - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@481c2a9e
DEBUG 2016-07-25 06:47:59,014 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG 2016-07-25 06:47:59,015 (CsrfFilter.java:106) - Invalid CSRF token found for http://localhost:8080/center/start-flow.do?execution=e1s1

在最后一行中,清楚地显示执行的最后一个过滤器是CsrfFilter,它是我们设置中14个过滤器中的4个过滤器。它会抛出错误Invalid CSRF token found for ....并取消过滤器链。如果我们在CsrfFilter中设置断点,我们也可以清楚地看到csrfToken实际上是null

作为一个快速解决方案,我们现在只是禁用了CSRF并对此表示满意:

<security:http auto-config="true" use-expressions="true">
    <!-- CSRF: Cross-site request forgery must be DISABLED when using web-flow!
         Web-flow request do not provide correct CSRF tokens!!! -->
    <security:csrf disabled="true"/>
    <security:intercept-url pattern="/**" access="permitAll" />
    <security:intercept-url pattern="/secure/**" access="hasRole('ROLE_USER')" />
    <security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
</security:http>

截至目前,我担心如果您需要CSRF,您需要提供自己的修复程序。关于webflow-2中关于CSRF的SO的讨论请参阅:here(有一些详细的安全问题here)。