CodeGym /Courses /Module 5. Spring /Lecture 110: Configuring Spring Security for Microservice...

Lecture 110: Configuring Spring Security for Microservices

Module 5. Spring
Level 18 , Lesson 9
Available

Microservices, as small self-contained modules, talk to each other to build complex systems. Security plays a key role here because microservices exchange data that can be sensitive. Without proper access setup you can easily leak data, make access-control mistakes, and ultimately lose user trust.

For working with microservices, Spring Security gives flexible mechanisms for protection and access control. Let's go through how to make our microservice systems not just functional but secure as well.

So, let's enable Spring Security and discuss the right approaches and practices.


A bit of theory

First, let's briefly review microservices' security needs:

  1. Authorization and authentication. You need to clearly identify who's making a request and whether that "someone" has the right to access the resource.
  2. Role and access management. For example, in our app admins see more data than regular users.
  3. Inter-service communication. One microservice must be sure that a request from another microservice actually comes from a trusted service.

In a microservice architecture we often split security into two levels:

  • External access — requests from a client (user) to the microservices.
  • Internal communications — interactions between microservices.

To solve security tasks we'll use a combo of Spring Security and JWT — the ideal duo for protection and easy configuration.


Practical part: configuring security in Spring Security

Step 1: Add Spring Security First, let's add the Spring Security dependency to our pom.xml:


<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

This dependency brings everything we need for basic security setup into our app.


Step 2: Create security configuration

For microservices we usually start with a Java-based configuration. Let's create a class where we'll configure Spring Security.


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;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable() // Disable CSRF for simplicity (only for APIs!)
            .authorizeRequests()
                .antMatchers("/public/**").permitAll() // Public access
                .antMatchers("/admin/**").hasRole("ADMIN") // Only for ADMIN role
                .anyRequest().authenticated() // All other requests must be authenticated
            .and()
            .httpBasic(); // Use basic authentication (to start)
    }
}

What we did here:

  1. Disabled CSRF (this is important because we're working with a REST API). Still, be careful — in production systems you should take CSRF into account.
  2. Configured public and protected routes. Now /public/** is open to everyone, while /admin/** is only for admins.

Step 3: Add in-memory users

Now we'll add a simple in-memory user setup. This is useful during development to quickly configure access.


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
        .withUser("user").password("{noop}password").roles("USER") // {noop} means the password is not encoded
        .and()
        .withUser("admin").password("{noop}admin").roles("ADMIN");
}

Now we have two users: "user" with password "password" who has the USER role, and "admin" with password "admin" who has the ADMIN role.

Step 4: Add JWT

Now let's add tokenization using JWT. JWT will replace basic authentication and let us manage access more flexibly.

Step 4.1: Add JWT dependencies

Update pom.xml to add a library for working with JWT:


<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt</artifactId>
  <version>0.9.1</version>
</dependency>

Step 4.2: Create a utility for JWT


import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

public class JwtUtil {
    private static final String SECRET_KEY = "super_secret_key";

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hours
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

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

Step 4.3: Configure a filter for JWT authentication


import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;

    public JwtFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
        String authHeader = request.getHeader("Authorization");

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            String username = jwtUtil.validateToken(token);

            if (username != null) {
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        filterChain.doFilter(request, response);
    }
}

Wrap-up

Now our app is ready to work with JWT for authentication and protecting microservices. You can test the API with a tool like Postman or curl by passing the JWT with requests. Goodbye, SQL injections in request headers! Spring Security's here to help keep everything safe.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION