Trong bài viết giới thiệu về Spring Security, chúng ta đã sử dụng một tập tin cấu hình và khai báo nó cùng với class filter DelegatingFilterProxy để enable Spring Security cho một ứng dụng web bất kỳ. Chúng ta cũng có thể làm được những điều này sử dụng code Java với các class WebSecurityConfigurerAdapter và AbstractSecurityWebApplicationInitializer, được hỗ trợ bởi Spring Security. Cụ thể như thế nào? Chúng ta sẽ tìm hiểu về nó trong bài viết này các bạn nhé!
Đầu tiên, mình sẽ tạo một project Spring MVC sử dụng các interface WebApplicationInitializer và WebMvcConfigurer để làm ví dụ như sau:
với các tập tin AppInitializer.java, SpringConfiguration.java và index.jsp có nội dung như sau:
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 |
Bây giờ chạy ứng dụng, các bạn sẽ thấy kết quả như sau:
Để làm việc với Spring Security, các bạn cần khai báo thêm các dependencies spring-security-web và spring-security-config như sau:
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> |
với:
1 2 3 4 |
<properties> ... <org.springframework.security-version>5.6.2</org.springframework.security-version> </properties> |
Chúng ta sẽ sử dụng class WebSecurityConfigurerAdapter để cấu hình cho phần authentication và authorization của Spring Security.
Class WebSecurityConfigurerAdapter là một abstract class implement interface WebSecurityConfigurer định nghĩa các cấu hình mặc định cần thiết cho Spring Security. Chúng ta cần sử dụng class này với annotation @EnableWebSecurity để enable hỗ trợ security cho ứng dụng web của chúng ta.
Bây giờ, mình sẽ tạo mới một class SpringSecurityConfiguration, annotated với annotation @EnableWebSecurity với nội dung ban đầu như sau:
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 { } |
Class WebSecurityConfigurerAdapter có các overloaded method configure() với các tham số khác nhau: AuthenticationManagerBuilder để cấu hình cho phần authentication, HttpSecurity cho phần authorization và WebSecurity để disable access các request tới resource của ứng dụng.
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 { } } |
Cho phần authentication thì class AuthenticationManagerBuilder được sử dụng để tạo mới AuthenticationManager, quản lý thông tin user đăng nhập ứng dụng. Class này hỗ trợ chúng ta có thể sử dụng user được lưu trữ in-memory, trong database hoặc LDAP. Để đơn giản, mình sẽ sử dụng user in-memory như sau:
1 2 3 4 |
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("khanh").password("{noop}123456").roles("ROLE_USER"); } |
Nếu các bạn muốn định nghĩa thêm user thì có thể sử dụng phương thức and() tiếp theo đoạn code trên, ví dụ:
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"); } |
Cho phần authorization thì class HttpSecurity được sử dụng để định nghĩa request nào được access bởi user với role nào. Ví dụ:
1 2 3 4 |
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/").hasRole("ROLE_USER"); } |
Tượng tự như phần định nghĩa thông tin user, các bạn cũng có thể thêm nhiều định nghĩa cho phần authorization như sau:
1 2 3 4 5 6 |
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/").hasRole("USER") .antMatchers("/admin/**").hasRole("ADMIN"); } |
Phần disable request tới resource của ứng dụng thì các bạn có thể disable request tới thư mục resources như sau:
1 2 3 4 |
@Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resources/**"); } |
Sau khi đã cấu hình xong cho phần authentication và authorization, chúng ta sẽ tiến hành đăng ký class DelegatingFilterProxy với Java web server thông qua Spring container. Chúng ta sẽ sử dụng class AbstractSecurityWebApplicationInitializer để làm điều này.
Các bạn chỉ cần tạo mới một class extends class AbstractSecurityWebApplicationInitializer là được:
1 2 3 4 5 6 7 |
package com.huongdanjava.springsecurity; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { } |
Spring sẽ tự động detect instance của class này trong quá trình khởi chạy ứng dụng để đăng ký class DelegatingFilterProxy để sử dụng springSecurityFilterChain trước bất kỳ các class Filter nào của Java web server.
OK, bây giờ nếu các bạn chạy ứng dụng, các bạn sẽ thấy kết quả như sau:
Ứng dụng của chúng ta đã được enable Spring Security rồi đó các bạn.
Để enable form login mặc định của Spring Security, các bạn cần thêm một đoạn code vào phương thức configure(HttpSecurity http) của class extend class WebSecurityConfigurerAdapter như sau:
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(); } |
Lúc này, chạy lại ứng dụng rồi request tới nó, các bạn sẽ thấy form login mặc định của Spring Security như sau:
Login bằng thông tin user đã khai báo trong phương thức configure(AuthenticationManagerBuilder auth), các bạn sẽ thấy được trang index của ứng dụng của chúng ta.