How can a microservice use the security config of another microservice

I have a user microservice dealing with everything related to users including security (create a User, login, reset password...). I'm using JWT Token for security.

My config security looks like this:


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomUserDetailsService customUserDetailsService;

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

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

    /**
     * the main Spring Security interface for authenticating a user
     *
     * @return the {@link AuthenticationManager}
     * @throws Exception
     */
    @Bean(BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * create an AuthenticationManager instance
     *
     * @param auth AuthenticationManagerBuilder used to create the instance of AuthenticationManager
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(customUserDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    /**
     * configure security functionality, add rules to protect resources
     * define what route can be accessed without authentication
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler)
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/h2-console/**")
                .permitAll()
                .antMatchers("/api/auth/**")
                .permitAll()
                .antMatchers(HttpMethod.GET, "/api/user/**")
                .permitAll()
                .anyRequest()
                .authenticated();

        // Add our custom JWT security filter
        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

What I want to do is to secure another microservice (which is a basic CRUD for now) using the user microservice.

I have created a feign interface in the CRUD microservice

@FeignClient(name="UserMicroservice", url="http://localhost:8080")
public interface UserClient {

    @PostMapping(value = "/api/auth/login")
    AuthTokenDto authenticateUser(@RequestBody LogInDto logInDto);
}

and a controller

@RestController
public class AuthController {

    @Autowired
    UserClient userClient;

    @PostMapping("/api/auth/login")
    public AuthTokenDto authenticate(@RequestBody LogInDto logInDto) {

        AuthTokenDto token = userClient.authenticateUser(logInDto);

        return token;
    }
}

This is successfull in calling the user microservice and getting the jwt token.

However I do not know how to have my CRUD microservice use the security config of the user microservice.

So, essentially what can I do to secure my CRUD microservice's endpoints using my user microservice?

So far I have been unable to find a solution on my own or searching the internet.

1 answer

  • answered 2019-07-18 13:35 AleKennedy

    I recommend you, that to save the token in a redis database and implement the security layer in all your microservices and each time that your microservices receive request, the class that implement JWT search in the redis if the token exist.

    I implemented like this

    public class JWTAuthorizationFilter extends BasicAuthenticationFilter{
    
    public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }
    
    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
                    throws IOException, ServletException {
            String header = req.getHeader(Constantes.HEADER_AUTHORIZACION_KEY);
            Logger.getLogger(JWTAuthorizationFilter.class.getCanonicalName()).log(Level.INFO, "HEADER: "+header);
            if (header == null || !header.startsWith(Constantes.TOKEN_BEARER_PREFIX)) {
                    chain.doFilter(req, res);
                    return;
            }
            UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(req, res);
    }
    
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
            String token = request.getHeader(Constantes.HEADER_AUTHORIZACION_KEY);
            Logger.getLogger(JWTAuthorizationFilter.class.getCanonicalName()).log(Level.INFO, "token: "+token);
            if (token != null) {
                    // Se procesa el token y se recupera el usuario.
                    Jedis jedis = new Jedis(SystemVariables.getDataBaseRedisIp());
                    String key = jedis.get(token);
                    Logger.getLogger(JWTAuthorizationFilter.class.getCanonicalName()).log(Level.INFO, "key: "+key);
                    String user = JWT.require(Algorithm.HMAC256(key)).build()
                            .verify(token.replace(Constantes.TOKEN_BEARER_PREFIX, ""))
                            .getSubject();
    
                    if (user != null) {
                            return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
                    }
                    return null;
            }
            return null;
    }
    

    And on each http request add the header Authorization with the token generated for example:

    Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU2NDEwNjMzNX0.HzG2nKUReCsrEZZOQLH8cuh3yfuP4VX0tkDvWTS8_s8