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
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.
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).
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.
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"

and finally select the bean
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With