Reputation: 170
I'm running a SpringBoot application with a the root class being annotated with @SpringBootApplication
, @EnableAutoConfiguration
.
I've created a UserRepositoryInterface
interface, which extends the CrudRepository
interface with my User JPA object. There is no implementation for this interface and there was no need for one yet. Neither are there any configuration files for anything in this Application. Except for the JPA DB connection, but that works.
public interface UsersRepositoryInterface extends CrudRepository<User, Long> {
// Query to search for users via email
List<User> findByEmail(@Param("email") String email);
}
And I've succesfully Autowired it into some REST endpoints. The problem appears, when I try to Autowire it into my security classes. I'm trying for authentication with JWT and it works. Now I want to call the database during the log-in process and I'm having an issue. Here are the classes:
First the WebSecurityConfiguererAdapter
class, where I add the paths to the filter. Note the line with "new JWTLoginFilter
", which is the class where I try to Autowire:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsServ;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
//Allow options pre-flight request
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// Allow POST request to /login
.antMatchers(HttpMethod.POST, "/login").permitAll()
// Others must be authenticated
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new JWTAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Change logging in from username+password to email+password
auth.userDetailsService(userDetailsServ);
}
}
And the JWTLoginFilter
class. I ommited some irrelevant code:
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private UsersRepositoryInterface userRepo;
public JWTLoginFilter(String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(
HttpServletRequest req, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
//Check if userRepo is injected
if(userRepo == null) {
System.out.println("Null");
}
AccountCredentials creds = new ObjectMapper()
.readValue(req.getInputStream(), AccountCredentials.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
creds.getEmail(),
creds.getPassword(),
Collections.emptyList()
)
);
}
}
The println
in JWTLoginFilter
will always return Null, when called upon.
Am I missing something?
SOLVED IT:
Works now.
Annotated the JWTLoginFilter with
@Component("someName")
And injected it in the WebSecurityConfig with
@Resource(name="someName")
private JWTLoginFilter myFilter;
Hardcoded the URL in the JWTLoginFilter constructor, but I still had to Autowire the AuthenticationManager from the WebSecurityConfig into the JWTLoginFilter.
First had to make the AuthenticationManager a Bean. Used the answer here: How To Inject AuthenticationManager using Java Configuration in a Custom Filter
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
Then injected it with answer here: Spring Security authenticationmanager must be specified - for custom filter
@Override
@Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
While removing the
setAuthenticationManager(authManager);
in the constructor in JWTLoginFilter
Upvotes: 2
Views: 5670
Reputation: 21
I Hope your problem has been resolved already. But I am adding a sample code snippet for reference for those who are facing the same issue.
When our filter contains Autowired dependencies, and instantiating our filter in spring configuration using new() would not autowire its dependencies as this won't be a string managed bean. Hence we need to autowire our filter in spring application configuration class , which in turn autowire its internal dependencies.
PFB the sample code for reference.
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Autowired
private MyFilter myFilter;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(MyApplication.class);
}
@Bean
public FilterRegistrationBean myFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(myFilter);
registration.addUrlPatterns("*");
return registration;
}
}
Filter:
@Component
public class MyFilter extends BaseFilter {
@Autowired
private EmployeeRepository employeeRepository;
//your code goes here
if(employeeRepository != null) {
System.out.println("employeeRepository is not null");
}
}
Upvotes: 2
Reputation: 120978
Well, what do you expect? You are creating the JWTLoginFilter
via the new
keyword. Spring does not do any wiring here at all. You should make this filter a @Bean
or @Component
or whatever else to make it a spring bean
and inject it into WebSecurityConfig
somehow.
Upvotes: 3