Reputation: 7749
I'm using JWT (Json Web Token)
to secure my Spring boot application.
There's a class which doesn't accept any bean.
First, I thought maybe the bean I want to inject is not defined. So I decided to print the list of beans names using spring ApplicationContext
. But I found out that even ApplicationContext
can not be injected into this class:
Any idea why this happens ?
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Autowired
private ApplicationContext applicationContext;
public JWTLoginFilter(String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req,
HttpServletResponse res) throws AuthenticationException,
IOException, ServletException {
CustomUserDetails creds = new ObjectMapper().readValue(
req.getInputStream(), CustomUserDetails.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(creds.getUsername(),
creds.getPassword()));
}
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res, FilterChain chain, Authentication auth) {
java.util.List s = Arrays.asList(applicationContext.getBeanDefinitionNames());
System.out.println(s);
tokenAuthenticationService.addAuthentication(res, auth.getName());
}
}
Upvotes: 1
Views: 841
Reputation: 7749
Well, I finally decided to change how these classes are designed. I made methods inside TokenAuthenticationService
static.
Upvotes: 0
Reputation: 49656
The JWTLoginFilter
has to be a bean as well to allow Spring to inject other beans into. Currently, Spring doesn't have any control over this. Marking the class with the @Component
/ @Service
/ @Repository
annotations (depends on what role your filter plays, I assume the @Component
is a good choice) is going to resolve the issue.
EDIT 1:
JWTLoginFilter required a bean of type
java.lang.String
that could not be found. Can a component have a constructor?
The problem: Spring tried to use a two-argument constructor to create a bean and was expected that these two arguments are its beans. But it's not true because there is no bean with the String
class.
The solution: You should define a non-argument constructor to allow Spring to make an untuned instance without issues. Then create setters to provide methods which Spring will use to inject needed dependencies.
EDIT 2:
The workaround is to define a String
bean (in a @Configuration
class) which will be injected into the JWTLoginFilter
constructor, but I'm not sure that your filter needs to have some external dependencies.
@Bean
public String getStringPatternBean() {
return "pattern";
}
Upvotes: 3