基于spring security container的身份验证,未找到身份验证提供程序

时间:2016-10-24 16:59:15

标签: spring tomcat spring-security jsf-2.2

环境:Tomcat 7.0.64,JSF 2.2.12,Spring框架4.3.3,Spring Security 4.1.3,Hibernate 5.2.2。

我正在尝试将security.xml从我们的其他应用程序转换为Java Config以在我的项目中使用,但它仍然存在此错误:

  

找不到org.springframework.security.authentication.UsernamePasswordAuthenticationToken

的AuthenticationProvider

来自SPRING_SECURITY_LAST_EXCEPTION。当应用程序重定向到SPRING_SECURITY_LAST_EXCEPTION时,我有条件地显示login.xhtml?error=true,否则,我在任何日志中都没有看到任何错误。

我们的Tomcat有一个处理身份验证的自定义领域。从我在doc中读到的内容,我需要使用J2EE过滤器来使用基于容器的身份验证。使用XML配置的另一个应用程序没有问题,但我不能让Java配置为我工作。

在调试期间,我可以看到authenticationProvider设置为auth.authenticationProvider,但auth.parentAuthenticationManagernull。我不确定这是否是问题的原因,但它应该是null吗?我应该在哪里设置断点来调试这个没有身份验证提供程序的问题?

的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">
    <display-name>App1</display-name>    
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <persistence-unit-ref>
        <persistence-unit-ref-name>jdbc/public_PostgreSQL</persistence-unit-ref-name>
        <persistence-unit-name>AppPU</persistence-unit-name>
    </persistence-unit-ref>    
    <resource-ref>
        <res-ref-name>jdbc/public_PostgreSQL</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>      
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>login.xhtml</welcome-file>
    </welcome-file-list>    
    <!-- =================================================================== -->
    <!-- JSF Params                                                          -->
    <!-- =================================================================== -->
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.CONFIG_FILES</param-name>
        <param-value>/WEB-INF/faces-config.xml</param-value>
    </context-param>    

    <!-- Use JSF view templates saved as *.xhtml, for use with Facelets -->
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>    
    <context-param>
        <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
        <param-value>true</param-value>
    </context-param>    
    <context-param>
        <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
    </context-param>
    <!-- =================================================================== -->
    <!-- Servlets                                                            -->
    <!-- =================================================================== -->        
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- =================================================================== -->
    <!-- Servlet Mappings                                                    -->
    <!-- =================================================================== -->    
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>    
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>    

    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.xhtml</form-login-page>
            <form-error-page>/login.xhtml?error=true</form-error-page>
        </form-login-config>
    </login-config>

    <!-- =================================================================== -->
    <!-- Spring/Security Params                                              -->
    <!-- =================================================================== -->
    <!-- Context Configuration locations for Spring XML files -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/applicationContext-resources.xml
            classpath:/applicationContext-service.xml
        </param-value>
    </context-param>    
    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
            <security-constraint>
        <web-resource-collection>
            <web-resource-name>Application</web-resource-name>
            <url-pattern>/faces/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
    </security-constraint>
    <!-- =================================================================== -->
    <!-- Listeners                                                           -->
    <!-- =================================================================== -->

    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>
</web-app>
要转换为Java Config的

security.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans:beans xmlns="http://www.springframework.org/schema/security" 
         xmlns:beans="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-4.1.xsd 
                             http://www.springframework.org/schema/security 
                             http://www.springframework.org/schema/security/spring-security-4.1.xsd"> 

<beans:bean id="entryPoint"
        class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint">
</beans:bean>

<http auto-config="false" use-expressions="true" entry-point-ref="entryPoint" create-session="stateless" disable-url-rewriting="true" > 
    <form-login login-page="/login.xhtml" login-processing-url="/login" authentication-failure-url="/login.xhtml?error=true"/>
    <anonymous />
    <logout logout-success-url="/login.xhtml?logout=true"/>

    <custom-filter position="PRE_AUTH_FILTER" ref="j2eeFilter" />
</http> 

<authentication-manager alias="authenticationManager">
    <authentication-provider ref='preauthAuthProvider'/>
</authentication-manager>

<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />

<beans:bean id="preauthAuthProvider"
        class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <beans:property name="preAuthenticatedUserDetailsService"
                ref="userDetailsServiceWrapper" />
    <beans:property name="throwExceptionWhenTokenRejected"
                value="true"/>
</beans:bean>

<beans:bean id="j2eeFilter"  class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
    <beans:property name="authenticationManager"
                ref="authenticationManager" />
</beans:bean>

<beans:bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
    <beans:constructor-arg ref="userDao"/>
</beans:bean>

<beans:bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter">
</beans:bean>

<global-method-security pre-post-annotations="enabled" />  

SecurityWebInitializer.java

public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer {

    // optionally override methods
    // This method is needed. 
    // We need to pass in WebSecurityConfig.class since we are not using Spring MVC
    public SecurityWebInitializer() {
        super(WebSecurityConfig.class);
    }
}

WebSecurityConfig.java

@Configuration
@EnableWebSecurity
@ImportResource({"classpath:applicationContext-service.xml",   "classpath:applicationContext-resources.xml"})
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan(basePackages = "com.test.app1") 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // Spring Security default header:
        //     Cache-Control: no-cache, no-store, max-age=0, must-revalidate
        //     Pragma: no-cache
        //     Expires: 0
        //     X-Content-Type-Options: nosniff
        //     Strict-Transport-Security: max-age=31536000 ; includeSubDomains
        //     X-Frame-Options: DENY
        //     X-XSS-Protection: 1; mode=block
        http
            .csrf().disable() // crsf is enabled by default
            .headers()
            .disable();
        http
            .addFilterAfter(j2eePreAuthenticatedProcessingFilter(), J2eePreAuthenticatedProcessingFilter.class)           
            .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());

        http
         .authorizeRequests()
            .antMatchers("/login*", "/javax.faces.resource/**", "/resources/**", "*.css", "*.png", "*.gif", "*.js").permitAll()
            .anyRequest().authenticated()
            .and()
         .formLogin()
            .loginProcessingUrl("/login") 
            .loginPage("/login.xhtml") 
            .defaultSuccessUrl("/index.xhtml")
            .successHandler(new AuthenticationSuccessHandlerImpl())
            .failureUrl("/login.xhtml?error=true")
            .permitAll()
            .and()
         .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/login.xhtml?logout=true")
            .clearAuthentication(true)
            .invalidateHttpSession(true)
            .permitAll();
    }

    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .authenticationProvider(preauthAuthProvider());
    }

    @Bean
    public Http403ForbiddenEntryPoint authenticationEntryPoint() {
        return new Http403ForbiddenEntryPoint();
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider preauthAuthProvider() throws Exception {
        PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider = new PreAuthenticatedAuthenticationProvider();
        preAuthenticatedAuthenticationProvider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
        preAuthenticatedAuthenticationProvider.setThrowExceptionWhenTokenRejected(true);
        return preAuthenticatedAuthenticationProvider;
    }


    @Autowired
    @Bean
    public UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> userDetailsServiceWrapper() throws Exception {        
        UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> userDetailsByNameServiceWrapper = new UserDetailsByNameServiceWrapper<>();
        userDetailsByNameServiceWrapper.setUserDetailsService(new UserDaoHibernate());
        return userDetailsByNameServiceWrapper;
    }

    @Autowired
    @Bean
    UserDetailsService userSecurityService() {
        return new UserDetailsServiceImpl();
    }

    @Bean(name = "authenticationManager")
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        List<AuthenticationProvider> providers = new ArrayList<AuthenticationProvider>();
        providers.add(preauthAuthProvider());
        return new ProviderManager(providers);
    }

    @Bean
    public J2eePreAuthenticatedProcessingFilter j2eePreAuthenticatedProcessingFilter() throws Exception {
        J2eePreAuthenticatedProcessingFilter filter = new J2eePreAuthenticatedProcessingFilter();
        filter.setAuthenticationManager(authenticationManager());
        filter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
        return filter;
    }
    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }
    @Bean
    public AuthenticatedVoter authenticatedVoter() {
        return new AuthenticatedVoter();
    }
}

0 个答案:

没有答案