Open In App

Spring Security Integration with Spring Boot

Last Updated : 30 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Spring Security is a powerful and customizable authentication and access control framework for Java applications. It provides comprehensive security services for Java EE-based enterprise software applications. This article will integrate Spring Security with a Spring Boot application, covering configuration, authentication, and securing RESTful APIs.

Implementation of Spring Security in a Spring Boot Application

Below is the step-by-step implementation of Spring Security in a Spring Boot application.

Step 1: Add Dependencies

Add the necessary dependencies to your project for Spring Boot and Spring Security.

Maven:

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Starter Security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

Gradle:

dependencies {
    // Spring Boot Starter Web
    implementation 'org.springframework.boot:spring-boot-starter-web'
    
    // Spring Boot Starter Security
    implementation 'org.springframework.boot:spring-boot-starter-security'
}

These dependencies include Spring Boot's web and security starters, which provide essential components for web applications and security features.

Step 2: Configure Spring Security

By default, Spring Security secures all endpoints and offers a simple authentication system. Create a configuration class to alter this.

Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll() // Allow access to home and root
                .anyRequest().authenticated() // All other requests need authentication
                .and()
            .formLogin()
                .loginPage("/login") // Custom login page
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user")
                .password(passwordEncoder().encode("password"))
                .roles("USER");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // Use BCrypt for password encoding
    }
}

Explanation:

  • @EnableWebSecurity provides the Spring MVC integration and turns on web security capability for Spring Security.
  • @Bean public PasswordEncoder passwordEncoder(), defines a PasswordEncoder bean that uses BCryptPasswordEncoder to encode and debug passwords. A reliable password hashing algorithm isbcryptt.

Step 3: Configure Authentication

Authentication protocols supported by Spring Security include JDBC, LDAP, OAuth2, and in-memory. WebSecurityConfigurerAdapter and overrides the configure(AuthenticationManagerBuilder auth) function to configure authentication.

Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("regularUser")
                .password(passwordEncoder().encode("userPass"))
                .roles("USER")
                .and()
                .withUser("superAdmin")
                .password(passwordEncoder().encode("adminPass"))
                .roles("ADMIN");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // Use BCrypt for password encoding
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll() // Public endpoints accessible without authentication
                .anyRequest().authenticated() // All other requests need authentication
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Explanation:

  • .antMatchers("/public/**").permitAll(), permits access to any URL beginning with "/public/" without authentication.
  • @Bean public PasswordEncoder passwordEncoder(), Uses BCryptPasswordEncoder to define a PasswordEncoder bean. This is a popular option for safely hashing passwords.

Step 4: Secure RESTful APIs

Use the same configure(HttpSecurity HTTP) method to secure RESTful APIs, but adjust the authentication mechanism (e.g., JWT or OAuth2) accordingly.

Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class CustomSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()  // Disable CSRF for stateless APIs
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)  // Stateless session management
                .and()
            .authorizeRequests()
                .antMatchers("/api/admin/**").hasAuthority("ROLE_ADMIN")  // Restrict to ADMIN role
                .antMatchers("/api/user/**").hasAnyAuthority("ROLE_USER", "ROLE_ADMIN")  // Allow USER and ADMIN roles
                .antMatchers("/api/public/**").permitAll()  // Public endpoints accessible to everyone
                .anyRequest().authenticated()  // Secure all other endpoints
                .and()
            .addFilterBefore(customJwtFilter(), UsernamePasswordAuthenticationFilter.class);  // Add JWT filter
    }

    @Bean
    public CustomJwtFilter customJwtFilter() {
        return new CustomJwtFilter();  // Custom JWT filter for authentication
    }

    // Additional configuration for JWT or OAuth2 can be added here
}

Explanation:

  • .csrf().disable(), Turns off the defense against Cross-Site Request Forgery (CSRF). This is common for stateless APIs, which do not require CSRF.
  • .addFilterBefore(customJwtFilter(), Adds a customized JWT filter before the default UsernamePasswordAuthenticationFilter (, UsernamePasswordAuthenticationFilter.class). We'll handle JWT-based authentication with this filter.

Step 5: Make User Details Service

You must put UserDetailsService into practice for a more complex configuration, such as one that uses a database for authentication.

Java
import org.springframework.beans.factory.annotation.Autowired;
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;

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository; // Assuming you have a UserRepository to fetch user data

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
    }
}

Explanation:

  • @Service identifies this class as a component of a Spring service. It means you may use dependency injection and component scanning in this class, which also offers business logic.
  • @Autowired private UserRepository userRepository injects an instance of UserRepository. It is believed that database activities paboutuser data are handled by this repository.

Step 6: Testing Security Configuration

To make sure your security setup functions as intended, you must test it. The spring-security-test module from Spring Security offers assistance with testing.

Java
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@WebMvcTest
public class AuthenticationTests {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser(username = "normalUser", roles = {"USER"})
    public void testAccessToUserDashboardWithUserRole() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user/home"))
            .andExpect(status().isOk());
    }

    @Test
    @WithMockUser(username = "normalUser", roles = {"USER"})
    public void testAccessToAdminDashboardWithUserRole() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/admin/home"))
            .andExpect(status().isForbidden());
    }
}

Explanation:

  • @SpringBootTest indicates that the class is a test for Spring Boot. For integration tests that need to have access to the application context, it launches the entire application backdrop.
  • MockMvc allows you to test answers and mimic HTTP requests without having to launch an entire HTTP server.

Note: If you want to go through a sample authentication project implementation of Spring Security, then read this article: Authentication and Authorization in Spring Boot 3.0 with Spring Security

Conclusion

In conclusion, with Spring Security Integration into a Spring Boot application, you can manage authorization and authentication with a strong framework that will protect your application.


Next Article

Similar Reads