I am trying to add Spring security with a personalized login page and database access to my Spring MVC application. It seems that my mapping is incorrect, as it cannot display j_spring_security_check .
To solve the problem, I looked at the following pages 1 , 2 , 3 , but so far I could not solve the problem.
If you don't have much time, read PART 2 below, this is where the edited section of the question begins. Otherwise, read both PART 1 and PART 2 .
PART 1
I also added the following lines to my web.xml , but the application returns the following exceptions.
<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> Caused by: java.lang.IllegalStateException: Duplicate Filter registration for 'springSecurityFilterChain'. Check to ensure the Filter is only configured once. at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.registerFilter(AbstractSecurityWebApplicationInitializer.java:215) at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.insertSpringSecurityFilterChain(AbstractSecurityWebApplicationInitializer.java:147) at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.onStartup(AbstractSecurityWebApplicationInitializer.java:121) at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5423) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 6 more Jun 13, 2015 2:44:54 PM org.apache.catalina.core.ContainerBase startInternal SEVERE: A child container failed during start java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]] at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:188) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.startup.Catalina.start(Catalina.java:691) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:322) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:456) Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) Caused by: org.apache.catalina.LifecycleException: A child container failed during start at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:800) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 6 more Jun 13, 2015 2:44:54 PM org.apache.catalina.startup.Catalina start SEVERE: The required Server component failed to start so Tomcat is unable to start. org.apache.catalina.LifecycleException: Failed to start component [StandardServer[8005]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154) at org.apache.catalina.startup.Catalina.start(Catalina.java:691) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:322) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:456) Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardService[Catalina]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 7 more Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 9 more Caused by: org.apache.catalina.LifecycleException: A child container failed during start at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 11 more
Without adding this filter after the form is submitted, the request will be captured by the controller.
@Controller public class MainController { @RequestMapping("/{viewName}") public String index(@PathVariable String viewName) { ... }
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app 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" version="3.0"> <listener> <listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class> </listener> <servlet> <servlet-name>my</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>my</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/config/my-security.xml </param-value> </context-param> </web-app>
my-security.xml
<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-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> <http auto-config="true" access-denied-page="/notFound.jsp" use-expressions="true"> <intercept-url pattern="/" access="permitAll" /> </http> <authentication-manager> <authentication-provider> <user-service> <user name="alex" password="123456" authorities="ROLE_USER" /> <user name="mkyong" password="123456" authorities="ROLE_USER, ROLE_ADMIN" /> </user-service> </authentication-provider> </authentication-manager> </beans:beans>
Appconfig.java
@EnableWebMvc @Configuration @ComponentScan({ "com.myproject.*" }) @EnableTransactionManagement @Import({ SecurityConfig.class }) public class AppConfig { @Bean public SessionFactory sessionFactory() { LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder( dataSource()); builder.scanPackages("com.myproject.model").addProperties( getHibernateProperties()); return builder.buildSessionFactory(); } private Properties getHibernateProperties() { Properties prop = new Properties(); prop.put("hibernate.format_sql", "true"); prop.put("hiberate.show_sql", "true"); prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"); return prop; } @Bean(name = "dataSource") public BasicDataSource dataSource() { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/test"); ds.setUsername("jack"); ds.setPassword("jack"); return ds; } @Bean public HibernateTransactionManager txManager() { return new HibernateTransactionManager(sessionFactory()); } }
SecurityConfig.java
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("userDetailsService") UserDetailsService userDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder( passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/profile/**") .access("hasRole('ADMIN')").and().formLogin() .loginPage("/signin").failureUrl("/signin?error") .usernameParameter("username").passwordParameter("password") .and().logout().logoutSuccessUrl("/index").and().csrf().and() .exceptionHandling().accessDeniedPage("/403"); } @Bean public PasswordEncoder passwordEncoder() { PasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder; } }
SpringMVCInitializer.java
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { AppConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
LoginController.java
@Controller public class LoginController { @RequestMapping(value = "/login", method = RequestMethod.GET) public ModelAndView login( @RequestParam(value = "error", required = false) String error, @RequestParam(value = "logout", required = false) String logout) { ModelAndView model = new ModelAndView(); if (error != null) { model.addObject("error", "Invalid username and password!"); } if (logout != null) { model.addObject("msg", "You've been logged out successfully."); } model.setViewName("login"); return model; } }
**
PART 2
Based on Thomas suggestions, I changed the code as follows
**
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app 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" version="3.0"> <listener> <listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class> </listener> <servlet> <servlet-name>my</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>my</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
Appconfig.java
@EnableWebMvc @Configuration @ComponentScan({ "com.myproject" }) @EnableTransactionManagement @Import({ SecurityConfig.class }) public class AppConfig { @Bean public SessionFactory sessionFactory() { LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder( dataSource()); builder.scanPackages("com.myproject.model").addProperties( getHibernateProperties()); return builder.buildSessionFactory(); } private Properties getHibernateProperties() { Properties prop = new Properties(); prop.put("hibernate.format_sql", "true"); prop.put("hiberate.show_sql", "true"); prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"); return prop; } @Bean(name = "dataSource") public BasicDataSource dataSource() { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/test"); ds.setUsername("jack"); ds.setPassword("jack"); return ds; } @Bean public HibernateTransactionManager txManager() { return new HibernateTransactionManager(sessionFactory()); } }
SecurityConfig.java
@Configuration @EnableWebMvcSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("userDetailsService") UserDetailsService userDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); // auth.userDetailsService(userDetailsService).passwordEncoder( // passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/profile/**") .access("hasRole('ADMIN')").and().formLogin() .loginPage("/login").failureUrl("/login?error") .and().logout().logoutSuccessUrl("/index").and().csrf().and() .exceptionHandling().accessDeniedPage("/403"); } @Bean public PasswordEncoder passwordEncoder() { PasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder; } }
SpringMVCInitializer.java
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { AppConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
Maincontroller
@Controller public class MainController { @RequestMapping("/{viewName}") public String index(@PathVariable String viewName) { System.err.println("View Name is :" + viewName); if (isValidView(viewName)) { return viewName; } return null; }
As for MainController, I process static pages like www.myproject.com/index, www.myproject.com/contactus, etc. My other question on this issue: here