Search code examples
javaspring-bootspring-securityjwt

Error creating bean with name authenticationTokenFilterBean: Unsatisfied dependency expressed through field tokenUtils


I want to implement Spring Security in my project. But I keep getting the same error no matter what I try.

I created necessary classes (TokenUtils, AuthenticationTokenFilter, SpringConfiguration). They are under the same package, but I'm getting the following error.

This is part of my Stack Trace where the problem occurs

2018-12-31 23:58:10.616 INFO 9952 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2018-12-31 23:58:11.444 ERROR 9952 --- [ main] o.s.b.web.embedded.tomcat.TomcatStarter : Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'authenticationTokenFilterBean': Unsatisfied dependency expressed through field 'tokenUtils'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.sbvtransport.sbvtransport.security.TokenUtils' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 2018-12-31 23:58:11.479 INFO 9952 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat] 2018-12-31 23:58:11.495 WARN 9952 --- [ main] o.a.c.loader.WebappClassLoaderBase : The web application [ROOT] appears to have started a thread named [HikariPool-1 housekeeper] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: [email protected]/jdk.internal.misc.Unsafe.park(Native Method) [email protected]/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234) [email protected]/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2123) [email protected]/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182) [email protected]/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899) [email protected]/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1054) [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114) [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [email protected]/java.lang.Thread.run(Thread.java:834) WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.apache.catalina.loader.WebappClassLoaderBase (file:/C:/Users/Danijela/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.12/tomcat-embed-core-9.0.12.jar) to field java.io.ObjectStreamClass$Caches.localDescs WARNING: Please consider reporting this to the maintainers of org.apache.catalina.loader.WebappClassLoaderBase WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release 2018-12-31 23:58:11.502 WARN 9952 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat 2018-12-31 23:58:11.502 INFO 9952 --- [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2018-12-31 23:58:11.502 INFO 9952 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2018-12-31 23:58:11.517 INFO 9952 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. 2018-12-31 23:58:11.533 INFO 9952 --- [ main] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-12-31 23:58:11.845 ERROR 9952 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

   Field tokenUtils in      com.sbvtransport.sbvtransport.security.AuthenticationTokenFilter required a bean of type 'com.sbvtransport.sbvtransport.security.TokenUtils' that could not be found.

   The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.sbvtransport.sbvtransport.security.TokenUtils' in your configuration.    
package com.sbvtransport.sbvtransport.security;

These are my Security classes:

AuthenticationTokenFilter

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;

public class AuthenticationTokenFilter  extends UsernamePasswordAuthenticationFilter{

@Autowired
TokenUtils tokenUtils;

@Autowired
private UserDetailsService userDetailsService;

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    String authToken = httpRequest.getHeader("Authorization");
    String username = tokenUtils.getUsernameFromToken(authToken);

    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
        UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
        if (tokenUtils.validateToken(authToken, userDetails)) {
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
    }

    chain.doFilter(request, response);
}

}

TokenUtils

package com.sbvtransport.sbvtransport.security;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;

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

public class TokenUtils {

@Value("SuperSecreat")
private String secret;

@Value("86400") // 24 hours(in seconds)
private Long expiration;

public String getUsernameFromToken(String token) {
    String username;
    try {
        Claims claims = this.getClaimsFromToken(token);
        username = claims.getSubject();
    } catch (Exception e) {
        username = null;
    }
    return username;
}

private Claims getClaimsFromToken(String token) {
    Claims claims;
    try {
        claims = Jwts.parser().setSigningKey(this.secret).parseClaimsJws(token).getBody();
    } catch (Exception e) {
        claims = null;
    }
    return claims;
}

public Date getExpirationDateFromToken(String token) {
    Date expirationDate;
    try {
        final Claims claims = this.getClaimsFromToken(token);
        expirationDate = claims.getExpiration();
    } catch (Exception e) {
        expirationDate = null;
    }
    return expirationDate;
}

private boolean isTokenExpired(String token) {
    final Date expirationDate = this.getExpirationDateFromToken(token);
    return expirationDate.before(new Date(System.currentTimeMillis()));
}

public boolean validateToken(String token, UserDetails userDetails) {
    final String username = getUsernameFromToken(token);
    return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
}

public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<String, Object>();
    claims.put("sub", userDetails.getUsername());
    claims.put("created", new Date(System.currentTimeMillis()));
    return Jwts.builder().setClaims(claims).setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
            .signWith(SignatureAlgorithm.HS512, secret).compact();
}

}

SecurityConfiguration

package com.sbvtransport.sbvtransport.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@SpringBootApplication
@Configuration
@EnableWebSecurity
@EnableAutoConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;

@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {

    authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
}

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

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

@Bean
public AuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
    AuthenticationTokenFilter authenticationTokenFilter = new AuthenticationTokenFilter();
    authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
    return authenticationTokenFilter;
}

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests().antMatchers("").permitAll();

    httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}

  }

It seems there is a problem with autowiring TokenUtils inside AuthenticationTokenFilter, but I also may be wrong.

I hope my question is clear enough, if I can do anything to improve it, please suggest it.


Solution

  • Error : Error message clearly says TokenUtils bean is not found

    'com.sbvtransport.sbvtransport.security.TokenUtils' that could not be found.

    You are missing @Component on TokenUtils, declaring class with @Component makes component scan to create singleton bean of this class in application context

    @Component
    public class TokenUtils {
    

    And @Configuration on AuthenticationTokenFilter

    @Configuration
    public class AuthenticationTokenFilter  extends UsernamePasswordAuthenticationFilter{
    

    @SpringBootApplication enables component scan in the package it is declared

    @EnableAutoConfiguration: enable Spring Boot’s auto-configuration mechanism

    @ComponentScan: enable @Component scan on the package where the application is located (see the best practices)

    @Configuration: allow to register extra beans in the context or import additional configuration classes

    The @SpringBootApplication annotation is equivalent to using @Configuration, @EnableAutoConfiguration, and @ComponentScan with their default attributes,