In the introduction to Spring Security, we used a configuration file and declared it with the DelegatingFilterProxy filter class to enable Spring Security for any web application. We can also do this using Java code with the WebSecurityConfigurerAdapter and AbstractSecurityWebApplicationInitializer classes, powered by Spring Security. How is it in detail? We will learn about it in this tutorial!
First, I will create a Spring MVC project using the WebApplicationInitializer and WebMvcConfigurer interfaces as an example:
with the AppInitializer.java, SpringConfiguration.java and index.jsp files with the following content:
AppInitializer.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.huongdanjava.springsecurity; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class AppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext sc) throws ServletException { AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext(); root.scan("com.huongdanjava.springsecurity"); sc.addListener(new ContextLoaderListener(root)); ServletRegistration.Dynamic appServlet = sc.addServlet("appServlet", new DispatcherServlet(new GenericWebApplicationContext())); appServlet.setLoadOnStartup(1); appServlet.addMapping("/"); } } |
SpringConfiguration.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.huongdanjava.springsecurity; import org.springframework.context.annotation.Bean; 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.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @EnableWebMvc @Configuration public class SpringConfiguration implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); } @Bean public ViewResolver viewResolver() { InternalResourceViewResolver bean = new InternalResourceViewResolver(); bean.setViewClass(JstlView.class); bean.setPrefix("/WEB-INF/views/"); bean.setSuffix(".jsp"); return bean; } } |
index.jsp:
1 |
Hello from Huong Dan Java |
Now run the application, you will see the following results:
To work with Spring Security, you need to declare the spring-security-web and spring-security-config dependencies as follows:
1 2 3 4 5 6 7 8 9 10 |
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${org.springframework.security-version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${org.springframework.security-version}</version> </dependency> |
with:
1 2 3 4 |
<properties> ... <org.springframework.security-version>5.6.2</org.springframework.security-version> </properties> |
We will use the WebSecurityConfigurerAdapter class to configure the authentication and authorization of Spring Security.
The WebSecurityConfigurerAdapter class is an abstract class that implements the WebSecurityConfigurer interface that defines the default configuration needed for Spring Security. We need to use this class with the @EnableWebSecurity annotation to enable security support for our web application.
Now, I will create a new SpringSecurityConfiguration class, annotated with the @EnableWebSecurity annotation with the following content:
1 2 3 4 5 6 7 8 9 |
package com.huongdanjava.springsecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @EnableWebSecurity public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter { } |
The WebSecurityConfigurerAdapter class has overloaded configure() methods with different parameters: AuthenticationManagerBuilder to configure authentication, HttpSecurity for authorization, and WebSecurity to disable access to application resources.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.huongdanjava.springsecurity; 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; @EnableWebSecurity public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { } @Override protected void configure(HttpSecurity http) throws Exception { } @Override public void configure(WebSecurity web) throws Exception { } } |
For authentication, the AuthenticationManagerBuilder class is used to create new AuthenticationManager, managing application login user information. This class allows us to use users which are stored in-memory, in database or LDAP. For simplicity, I will use the user in-memory as follows:
1 2 3 4 |
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("khanh").password("{noop}123456").roles("ROLE_USER"); } |
If you want to define more users, you can use the and() method following the above code, for example:
1 2 3 4 5 6 7 |
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("khanh").password("{noop}123456").roles("USER") .and() .withUser("thanh").password("{noop}123456").roles("ADMIN"); } |
For authorization, the HttpSecurity class is used to define which requests are accessed by the user with which role. For example:
1 2 3 4 |
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/").hasRole("ROLE_USER"); } |
Similar to the definition of user information, you can also add more definitions for the authorization as follows:
1 2 3 4 5 6 |
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/").hasRole("USER") .antMatchers("/admin/**").hasRole("ADMIN"); } |
The disable request to the resource of the application, you can disable the request to the resources directory as follows:
1 2 3 4 |
@Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resources/**"); } |
After configuring authentication and authorization, we will register the DelegatingFilterProxy class with the Java web server through the Spring container. We will use class AbstractSecurityWebApplicationInitializer to do this.
You just need to create a new class extending class AbstractSecurityWebApplicationInitializer:
1 2 3 4 5 6 7 |
package com.huongdanjava.springsecurity; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { } |
Spring will automatically detect the instance of this class during application launch to register DelegatingFilterProxy class to use springSecurityFilterChain before any Java web server Filter classes.
OK, now if you run the application, you will see the following result:
Our application has Spring Security enabled.
To enable Spring Security’s default login form, you need to add a piece of code to the configure(HttpSecurity http) method of the extend class WebSecurityConfigurerAdapter class as follows:
1 2 3 4 5 6 7 |
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/").hasRole("USER") .antMatchers("/admin/**").hasRole("ADMIN") .and().formLogin(); } |
Now run the application and request to it, you will see the default login form of Spring Security as follows:
Log in with the user information declared in the configure(AuthenticationManagerBuilder auth) method, you will see the index page of our application.