Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot 2+ Could not Autowire. There is more than one bean of 'UserDetailsService'

Hello Everyone i'm new in spring security and jwt. I'm implementing Jwt in my spring boot project to secure user login and i'm using spring boot 2.1.5 and i don't know much about new bean restriction in spring boot 2+ . I need some help .. here i'm trying to @Autowired UserDetailsService and code run fine ..and result is also fine.. but intellij shows error at

@Autowired UserDetailsService jwtUserDetailsService

saying ... Could not autowire. There is more than one bean of UserDetailsService type.

Can anyone explain me what what happens wrong here why i can't autowired and why and what are the Autowired restriction in spring boot 2+ ?

And thanks in advance

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtFilter jwtFilter;

    @Autowired
    private UserDetailsService jwtUserDetailsService; // here i got error only

    @Autowired
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/api/user/add", "/generate").permitAll().anyRequest().authenticated().and()            .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

my customUserDetailService is

@Service
public class JwtUserDetailService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

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

    }
}

My JwtController class which expose restend point to generate jwt token


@CrossOrigin
@RestController
public class JwtController {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUserDetailService jwtUserDetailService;

    @PostMapping(value = "/generate")
    public ResponseEntity<?> generateToken(@RequestBody JwtRequest jwtRequest) throws Exception {
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(jwtRequest.getUsername(),
                    jwtRequest.getPassword()));
        } catch (DisabledException e) {
            throw new Exception("USER_DISABLED", e);
        } catch (BadCredentialsException e) {
            throw new Exception("INVAILD_CREDENTIALS", e);
        }
        final UserDetails userDetails = jwtUserDetailService.loadUserByUsername(jwtRequest.getUsername());
        final String token = jwtUtils.generateToken(userDetails);

        return ResponseEntity.ok(new JwtResponse(token));
    }
}

My JwtFilter Class

@Component
public class JwtFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUserDetailService jwtUserDetailService;

    @Autowired
    private JwtUtils jwtUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        final String requestTokenHeader = request.getHeader("Authorization");

        String username = null;
        String jwtToken = null;

        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtUtils.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                System.out.println("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                System.out.println("JWT Token has expired");
            }
        } else {
            logger.warn("JWT Token does not begin with Bearer String");
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.jwtUserDetailService.loadUserByUsername(username);

            if (jwtUtils.validate(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
               SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }

}

Other thing as just normal like entity, repository, and some secured restend points

like image 283
bkvishal Avatar asked Jun 21 '19 11:06

bkvishal


People also ask

Can I Autowire more than one bean?

When a bean implementation exists both in the production and test codes, IntelliJ will mark @Autowired instances of this bean as "cannot autowire, more than one bean...". This is of course incorrect, as the test implementation will never be deployed in a production environment.

Can't Autowire there more than?

IDEA reports "Could not Autowire: There is more than one bean...", but there is only one Bean. The other Bean of same type that IDEA references is in moduleA's test-context. xml, but there is no dependency defined between moduleA and moduleB (in test scope).

Can you Autowire by type when more than one?

If there is more than one, a fatal exception is thrown, and this indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set.


2 Answers

I got the same error in another context. The reason was the Idea don´t know which bean of type 'UserDetailsService' to use. My solution is through annotation Qualifier:

@Qualifier("beanNameWhichYouWantUse")
@Autowired
private UserDetailsService jwtUserDetailsService;

If use Idea: give mouse point on the error, select from context menu:

"More actions" -> "Add qualifier"

enter image description here

and finally select the bean

like image 23
RHronza Avatar answered Sep 23 '22 16:09

RHronza


UserDetailsService was provided by spring. To Autowire you need to configure it with.

@Bean
public UserDetailsService getUserDetails(){
   return new JwtUserDetailService(); // Implementation class
}

If you are not interested in Bean Configuration. you can autowire JwtUserDetailService directly.

@Autowired
private JwtUserDetailService jwtUserDetailsService;
like image 192
GnanaJeyam Avatar answered Sep 23 '22 16:09

GnanaJeyam