Spring安全登录处理url不可用

Spring安全登录处理url不可用,spring,spring-security,jsf-2,Spring,Spring Security,Jsf 2,我有一个项目,其中Spring与JSF一起使用(使用PrimeFaces)。到目前为止,我们已经将xml配置用于Spring安全性,但我的任务是将其移植到基于java的配置 我现在从applicationContext.xml中的xml配置开始: <!-- Security Config --> <security:http security="none" pattern="/javax.faces.resource/**"/> <security:http aut

我有一个项目,其中Spring与JSF一起使用(使用PrimeFaces)。到目前为止,我们已经将xml配置用于Spring安全性,但我的任务是将其移植到基于java的配置

我现在从
applicationContext.xml
中的xml配置开始:

<!-- Security Config -->
<security:http security="none" pattern="/javax.faces.resource/**"/>
<security:http auto-config="true" use-expressions="true">
    <security:intercept-url pattern="/login.xhtml" access="permitAll"/>
    <security:intercept-url pattern="/**" access="permitAll"/>

    <security:form-login login-page="/login.xhtml" 
        login-processing-url="/do_login"
        authentication-failure-url="/login.xhtml"
        authentication-success-handler-ref="authSuccessHandler"
        username-parameter="email" 
        password-parameter="password"/>
    <security:logout logout-success-url="/login.xhtml"
        logout-url="/do_logout"
        delete-cookies="JSESSIONID"/>
</security:http>

<bean id="userDetails" class="com.madmob.madmoney.security.UserDetailsServiceImpl"></bean>
<bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
    <constructor-arg name="strength" value="10" />
</bean>
<bean id="authSuccessHandler" class="com.madmob.madmoney.security.UserAuthenticationSuccessHandler"></bean>

<security:authentication-manager>
    <security:authentication-provider user-service-ref="userDetails">
        <security:password-encoder ref="encoder" />    
    </security:authentication-provider>
</security:authentication-manager>
<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>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>
到以下基于java的配置:

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserAuthenticationSuccessHandler authSuccessHandler;
    @Autowired
    DataSource dataSource;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) 
        throws Exception {
        auth.jdbcAuthentication().usersByUsernameQuery("SELECT email, passowrd, enabled FROM app_user WHERE email = ?")
        .authoritiesByUsernameQuery("SELECT role_name FROM role WHERE role_id = (SELECT role_id FROM user_role WHERE email = ?)")
        .dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder(10));
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/javax.faces.resource/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();

        http.authorizeRequests().anyRequest().authenticated()
        .and()
        .formLogin().loginPage("/login.xhtml").loginProcessingUrl("/do_login")
        .failureUrl("/login.xhtml").successHandler(authSuccessHandler)
        .usernameParameter("email").passwordParameter("password").permitAll()
        .and()
        .logout().logoutSuccessUrl("/login.xhtml").logoutUrl("/do_logout")
        .deleteCookies("JSESSIONID");

        // temp user add form
        // TODO remove
        http.antMatcher("/userForm.xhtml").authorizeRequests().anyRequest().permitAll();
    }
}

以及我的支持bean中的登录方法:

/**
 * Forwards login parameters to Spring Security
 */
public void login(ActionEvent loginEvt){
    // setup external context
    logger.info("Starting login");
    ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

    // setup dispatcher for spring security
    logger.info("Setup dispatcher");
    RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
            .getRequestDispatcher("/do_login");

    try {
        // forward request
        logger.info("Forwarding request to spring security");
        dispatcher.forward((ServletRequest) context.getRequest(), 
                (ServletResponse) context.getResponse());
    } catch (ServletException sEx) {
        logger.error("The servlet has encountered a problem", sEx);
    } catch (IOException ioEx) {
        logger.error("An I/O error has occured", ioEx);
    } catch (Exception ex) {
        logger.error("An error has occured", ex);
    }

    // finish response
    FacesContext.getCurrentInstance().responseComplete();
}
这在Java1.8、Tomcat7、Spring和SpringSecurity3.2.5、JSF2.1和PrimeFaces5上运行

遇到问题后我尝试过的事情:

  • 添加了
    SpringSecurityInitializer
    ,因为最初我只使用了
    SecurityConfig
  • 尝试使用默认的Spring安全url(
    j_Spring_Security_check
    ),方法是不指定处理url并转发到该url
  • 残疾csrf
  • getSecurityDispatcherTypes
    方法添加到
    SpringSecurityInitializer
    以匹配web.xml中的配置
  • 在寻找解决方案的过程中,会遇到其他各种较小的问题

    • 我发现了这个问题。问题在于:

      http.antMatcher("/userForm.xhtml").authorizeRequests().anyRequest().permitAll();
      
      从外观上看,这完全是我对方法的错误链接。我真的不明白为什么它会导致登录处理url找不到问题,而不仅仅是意外的访问行为,但我将该方法的整个片段更改为如下所示:

      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.csrf().disable()
          .authorizeRequests().antMatchers("/userForm.xhtml").permitAll() //TODO remove temp user add form
          .anyRequest().authenticated()
          .and()
          .formLogin().loginPage("/login.xhtml").loginProcessingUrl("/do_login")
          .failureUrl("/login.xhtml").successHandler(authSuccessHandler)
          .usernameParameter("email").passwordParameter("password").permitAll()
          .and()
          .logout().logoutSuccessUrl("/login.xhtml").logoutUrl("/do_logout")
          .deleteCookies("JSESSIONID");
      }
      

      这当然也更有意义,但我最初将它们分开,因为正如注释所指定的那样,
      userForm.xhtml
      是临时的。

      可以在不进行任何配置的情况下引导Spring安全性。您应该调用
      AbstractSecurityWebApplicationInitializer(Class…configurationClasses)
      构造函数,而不是默认的无参数构造函数。或者,如果您有另一种加载
      ContextLoaderListener
      的方法,请将配置类添加到该类中。
      ContextLoaderListener
      是在我的
      web.xml
      中定义的,因此如果我调用该构造函数,我会得到一个异常,因为已经存在根应用程序上下文,我不知道接下来如何添加配置。注意就我所知,
      @EnableWebSecurity
      注释应该处理这个问题,还是我遗漏了什么?(这个包是组件扫描的一部分,但是我在用xml手动定义bean时也遇到了同样的问题)如果您的配置没有加载,您可以在上面添加任意多的注释,而不会产生任何效果。因此,请确保已加载配置(尽管加载了其他内容,但您的应用程序将无法启动,并显示一条消息,说明未定义名为
      springSecurityFilterChain
      的bean).我已通过调试确认
      SecurityConfig
      中的
      configure
      三个方法都已执行,因此我假设这意味着它已加载。如果没有,是否有其他方法可以检查以确认是否有?
      http.antMatcher("/userForm.xhtml").authorizeRequests().anyRequest().permitAll();
      
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.csrf().disable()
          .authorizeRequests().antMatchers("/userForm.xhtml").permitAll() //TODO remove temp user add form
          .anyRequest().authenticated()
          .and()
          .formLogin().loginPage("/login.xhtml").loginProcessingUrl("/do_login")
          .failureUrl("/login.xhtml").successHandler(authSuccessHandler)
          .usernameParameter("email").passwordParameter("password").permitAll()
          .and()
          .logout().logoutSuccessUrl("/login.xhtml").logoutUrl("/do_logout")
          .deleteCookies("JSESSIONID");
      }