Spring Security and JWT

Spring Security and JWT

Spring Boot is a framework for building web applications using the Spring Framework. It provides a simple and easy-to-use approach for building standalone, production-grade Spring-based applications. One of the key features of Spring Boot is its built-in support for security.

Spring Security is a framework that provides authentication and authorization for Spring-based applications. It is designed to be extensible and customizable, allowing developers to easily secure their applications with minimal configuration. With Spring Boot, it is easy to add security to your application with minimal configuration.

Here's an example of how to secure a Spring Boot application using Spring Security:

  1. Add the Spring Security starter to your application's dependencies:
Copy code<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  1. Add a security configuration class that extends WebSecurityConfigurerAdapter:
Copy code@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

This configuration class tells Spring Security to:

  • Allow access to the "/" and "/home" URLs without authentication.

  • Require authentication for all other URLs.

  • Use a login page at the "/login" URL.

  • Use a UserDetailsService to load user information for authentication.

  • Use the BCrypt password encoder for password encoding

  1. Create a UserDetailsService implementation to load user information from a database:
Copy code@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(username);
        }
        return new CustomUserDetails(user);
    }
}

This is just a basic example of securing a Spring Boot application using Spring Security, and it's possible to configure additional features like role-based access control, session management, and more.

It's worth noting that the above example is a basic one, in a real application, you will have to handle more complex security such as handling CSRF, CORS, etc and also you need to consider using a more advanced authentication method like OAuth2, JWT and many other.

JWT

JSON Web Token (JWT) is a standard for creating compact, self-contained tokens that are used to securely transmit information between parties. JWT can be used for authentication and authorization purposes in a Spring Boot application. Using JWT, you can authenticate a user and create a token that contains the user's identity and other claims, and then use that token to authenticate the user on subsequent requests.

Here is an example of how to use JWT for authentication in a Spring Boot application:

  1. Add the following dependencies to your project's pom.xml file:
Copy code<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
  1. Create a JWT service class that generates and validates JWT tokens:
Copy code@Service
public class JwtService {

    private final String SECRET_KEY = "secret-key";

    public String generateToken(String username) {
        Claims claims = Jwts.claims().setSubject(username);
        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public String parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }
}

This JWT service class provides two methods generate token and parseToken. generate token method takes the username as input and generates a JWT token. parseToken method takes the JWT token and extracts the username from it.

  1. Create a filter that intercepts incoming requests and verifies the JWT token:
Copy code@Component
public class JwtFilter extends OncePerRequestFilter {

    @Autowired
    private JwtService jwtService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authorizationHeader = request.getHeader("Authorization");
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = authorizationHeader.substring(7);
        String username = jwtService.parseToken(token);

        if (username != null) {
            request.setAttribute("username", username);
        }

        filterChain.doFilter(request, response);
    }
}

This filter checks whether the incoming request contains a Authorization header and if it starts with Bearer , it extracts the token and sends it to the parse token method, which will parse and extract the username. If a username is returned, the filter sets it as a request attribute, which can be used for authentication and authorization.

  1. Enable the filter by adding the following line to your application's main class:
Copy code@ComponentScan(basePackages = {"your package where the filter is located"})

This will enable Spring Boot to scan your package and register the filter as a Bean.