0

I got error while running this code, there is an injection cycle in the code but I cannot find it. btw, I'm new with Spring. How can I solve this problem? And any good documentation about it ?

Here is my code;

WebSecurityConfiguration class:

package com.trendyol.app;

import com.trendyol.app.auth.JwtTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true) //Tüm methodlarımızdan önce security devreye girer
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    ///////////////////
    @Autowired
    private JwtTokenFilter jwtTokenFilter;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    public void configurePasswordEncoder(AuthenticationManagerBuilder builder  ) throws Exception{
        builder.userDetailsService(userDetailsService).passwordEncoder(getBCryptPasswordEncoder());
    }
    ///////////////////
    @Bean
    public BCryptPasswordEncoder getBCryptPasswordEncoder(){
       return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager getAuthenticationManager() throws Exception{
        return super.authenticationManagerBean();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/login") //bu adress hariç
                .authenticated()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);

    }
}

UserDetailsService:

package com.trendyol.app.auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;


@Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
    private Map<String,String > users=new HashMap<>();

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;


    @PostConstruct
    public void init(){
        users.put("temelt", passwordEncoder.encode("123"));
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if(users.containsKey(username)){
            return new User(username,users.get(username),new ArrayList<>());
        }
        throw new UsernameNotFoundException(username);
    }
}

LOGs: Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐ | webSecurityConfiguration (field private org.springframework.security.core.userdetails.UserDetailsService com.trendyol.app.WebSecurityConfiguration.userDetailsService) ↑ ↓ | userDetailsService (field private org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder com.trendyol.app.auth.UserDetailsService.passwordEncoder) └─────┘

4
  • 1
    Your security configuration needs the UserDetailsService, which in turn needs a PasswordEncoder which is created by the configuration. Hence a cycle.
    – M. Deinum
    Commented Sep 15, 2022 at 6:45
  • how can I solve it? :)) Commented Sep 15, 2022 at 6:48
  • 2
    Remove the Bean creation of BCryptPasswordEncoder from WebSecurityConfiguration and put it in a separate Configuration class
    – Arie
    Commented Sep 15, 2022 at 6:54
  • 1
    By moving the creation of the password encoder to a seperate configuration class. Tip also change your UserDetailsService to use a PasswordEncoder (the interface) instead of the concrete implementation (this won't solve it but is better).
    – M. Deinum
    Commented Sep 15, 2022 at 7:05

1 Answer 1

1

Have you tried marking your PasswordEncoder with the @Lazy tag instead of the @Autowired tag? From the docs:

Indicates whether a bean is to be lazily initialized.

I had a similar problem and changing to @Lazy was one way I solved the problem. In your case it would look something like:

@Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
    private Map<String,String > users=new HashMap<>();

    @Lazy
    private BCryptPasswordEncoder passwordEncoder;


    @PostConstruct
    public void init(){

See more here: Spring Lazy Annotation

Not the answer you're looking for? Browse other questions tagged or ask your own question.