简体   繁体   中英

Initialize Spring-Security with SpringMVC

I have a SpringMVC project (working). I decided that I want test spring-security library and I get it to my project. Now, I am getting this error:

    INFORMACIÓN: Starting Servlet Engine: Apache Tomcat/8.0.36
jul 27, 2017 7:17:31 PM org.apache.jasper.servlet.TldScanner scanJars
INFORMACIÓN: Al menos un JAR, que se ha explorado buscando TLDs, aún no contenía TLDs. Activar historial de depuración para este historiador para una completa lista de los JARs que fueron explorados y de los que nos se halló TLDs. Saltarse JARs no necesarios durante la exploración puede dar lugar a una mejora de tiempo significativa en el arranque y compilación de JSP .
jul 27, 2017 7:17:31 PM org.apache.catalina.core.ApplicationContext log
INFORMACIÓN: 1 Spring WebApplicationInitializers detected on classpath
jul 27, 2017 7:17:31 PM org.apache.catalina.core.ApplicationContext log
INFORMACIÓN: Initializing Spring root WebApplicationContext
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
INFO : org.springframework.web.context.support.XmlWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Thu Jul 27 19:17:31 CEST 2017]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/root-context.xml]
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 255 ms
jul 27, 2017 7:17:32 PM org.apache.catalina.core.StandardContext filterStart
GRAVE: Excepción arrancando filtro springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1084)

I tried fix it adding this to my web.xml file (of my spring-mvc project) but then tomcats crash in fatal error (without detail), works fine again when I removed this code:

<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>

My security config is this:

SecurityConfig.java (My spring-security class)

    package com.myproject.security;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("dataSource")
    DataSource dataSource;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests()
                .antMatchers("/", "/register", "/login").access("hasRole('DEFAULT')")
                .antMatchers("/web").access("hasRole('USER')")
                .antMatchers("/admin").access("hasRole('ADMIN')")
                .anyRequest().permitAll()
            .and()
                .formLogin()
                    .loginPage("/login")
                    .usernameParameter("username")
                    .passwordParameter("password")
            .and() 
                .logout()
                    .logoutSuccessUrl("/login?logout")
            .and()
                .exceptionHandling().accessDeniedPage("/403")
            .and()
                .csrf()
            .and()
                .cors();
        // @formatter:on
    }
}

CustomUserDetailService.java My user-roles service (for spring-security use)

    package com.everyhuman.security;

    import java.util.ArrayList;
    import java.util.List;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;

    import com.myproject.web.register.service.ServiceUser;
    import com.myproject.web.users.dto.DTORoles;
    import com.myproject.web.users.dto.DTOUser;


    @Service("customUserDetailService")
    public class CustomUserDetailService implements UserDetailsService {

        private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailService.class);

        @Autowired
        private ServiceUser serviceUser;

        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            DTOUser user = serviceUser.findUserByUsername(username);
            if (user == null) {
                logger.info("User not found");
                throw new UsernameNotFoundException("Username not found");
            }

            /*
             * Devolvemos un usuario securizado por spring
             */
            return new User(user.getUsername(), user.getPassword(), getGrantedAuthorities(user));
        }

        /**
         * Obtiene los roles del usuario
         * 
         * @param user
         * @return
         */
        private List<GrantedAuthority> getGrantedAuthorities(DTOUser user) {
            List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

            for (DTORoles userProfile : user.getRoles()) {
                authorities.add(new SimpleGrantedAuthority(userProfile.toString()));
            }
            return authorities;
        }

    }

SecurityWebApplicationInitializer.java (This class is for initialize Spring-Security)

    package com.myproject.security;

    import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

    public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    }

This my spring config:

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

    <annotation-driven />

    <resources mapping="/resources/**" location="/resources/" />

    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="com.myproject">
        <context:include-filter type="regex" expression="com.myproject.*.controller.*"/>
    </context:component-scan>

    <context:property-placeholder location="classpath:ehconf/*.properties" />

    <beans:bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="packagesToScan" value = "com.myproject.web" />
        <beans:property name="jpaVendorAdapter">
            <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </beans:property>
        <beans:property name="jpaProperties">
            <beans:props>
                <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</beans:prop>
            </beans:props>
        </beans:property>
   </beans:bean>

   <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <beans:property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
      <beans:property name="url" value="jdbc:mysql://localhost:3306/ehdatabase?serverTimezone=UTC" />
      <beans:property name="username" value="ehdatabase" />
      <beans:property name="password" value="ehdatabase123" />
   </beans:bean>

   <beans:bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
      <beans:property name="entityManagerFactory" ref="myEmf" />
   </beans:bean>

   <tx:annotation-driven />

   <beans:bean id="persistenceExceptionTranslationPostProcessor" 
   class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

</beans:beans>

And this my web.xml config:

    <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/root-context.xml
            <!-- /WEB-INF/spring/spring-security.xml -->
        </param-value>
    </context-param>

<!--    <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> -->

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Processes application requests -->
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

I recommend that you stick to Java Config since you are using Tomcat 8

Note that the XML security part is not required if you have

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

So you can just delete

<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>

Then, make sure that the package, which contains the secuirty configuration is added to the component scan

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.myproject.security")
public class HelloWorldConfiguration {

    @Bean
    public ViewResolver viewResolver() {
        //InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        //viewResolver.setViewClass(JstlView.class);
        //viewResolver.setPrefix("/WEB-INF/views/");
        //viewResolver.setSuffix(".jsp");
        // Set View Resolver

        return viewResolver;
    }

}

You can also delete the web.xml and use this instead

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { HelloWorldConfiguration.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

}

For the complete example check http://websystique.com/spring-security/spring-security-4-hello-world-annotation-xml-example/

For JPA Config you can add something like this

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = { "com.myproject.repository" })
public class PersistenceJPAConfig {
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { "com.myproject.jpa.entites"});

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;
    }

    private DatabasePopulator createDatabasePopulator() {
        ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
        databasePopulator.setContinueOnError(true);
        databasePopulator.addScript(new ClassPathResource("dropdownlist.sql"));
//        databasePopulator.addScript(new ClassPathResource("persistentlogins.sql"));
//        databasePopulator.addScript(new ClassPathResource("countries.sql"));
//        databasePopulator.addScript(new ClassPathResource("states.sql"));
//        databasePopulator.addScript(new ClassPathResource("cities.sql"));

        return databasePopulator;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
//      dataSource.setDriverClassName("com.mysql.jdbc.Driver");
//      dataSource.setUrl("jdbc:mysql://localhost:3306/spring_jpa");
//      dataSource.setUsername("tutorialuser");
//      dataSource.setPassword("tutorialmy5ql");
        dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        dataSource.setUrl("jdbc:sqlserver://localhost\\SQLEXPRESS;databaseName=ContractTracker");
        dataSource.setUsername("ctReader");
        dataSource.setPassword("ctreader");

        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);

        DatabasePopulatorUtils.execute(createDatabasePopulator(), dataSource());

        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.SQLServerDialect");
        return properties;
    }
}

EDITED: Have you tried to add the bean deffinition?

<bean id="springSecurityFilterChain" class="org.springframework.web.filter.DelegatingFilterProxy"/>

Another possible fail is that I can't see in your config the listener that starts the spring context:

<listener>
  <listener-class>
    org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>

Check the Spring page for more information.

OLD: I can't add a comment due to low reputation, so can you post your web.xml and your security.xml please?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM