I have a custom UserDetailsService:
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private AccountRepository accountRepository;
@Autowired
private PasswordEncoder passwordEncoder;
private static Logger logger = LoggerFactory.getLogger(JWTLoginFilter.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
CustomUserDetails account = accountRepository.findByUsername(username);
if (account != null) {
return account;
} else {
throw new UsernameNotFoundException("could not find the user '" + username + "'");
}
}
public void saveUser(String userName, String password) {
CustomUserDetails userDetails = new CustomUserDetails(userName, passwordEncoder.encode(password), true, true, true,true, AuthorityUtils.commaSeparatedStringToAuthorityList("USER_ROLE"));
accountRepository.save(userDetails);
logger.debug("New user with username " + userName + " was created");
}
}
and I have a sign up filter (which handles creating new users) and extends AbstractAuthenticationProcessingFilter
:
public class JWTSignupFilter extends AbstractAuthenticationProcessingFilter {
@Autowired
private CustomUserDetailsService userDetailService;
private static Logger logger = LoggerFactory.getLogger(JWTLoginFilter.class);
public JWTSignupFilter(String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url, HttpMethod.POST.toString()));
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
CustomUserDetails creds = new ObjectMapper().readValue(request.getInputStream(), CustomUserDetails.class);
if (userDetailService.loadUserByUsername(creds.getUsername()) != null) {
logger.debug("Duplicate username " + creds.getUsername());
throw new AuthenticationException("Duplicate username") {
private static final long serialVersionUID = 1L;
};
}
userDetailService.saveUser(creds.getUsername(), creds.getPassword());
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),creds.getPassword()));
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
TokenAuthenticationService.addAuthentication(response, auth.getName());
chain.doFilter(request, response);
}
}
I get null pointer exception when the execution reaches userDetailService.loadUserByUsername
, which means autowiring didn't work.
I tried implementing ApplicationContextAware
like the following, but it is still Null
. I also annotated JWTSignupFilter
with @Service
but it didn't work either. Any idea how to fix this issue ?
public class JWTSignupFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {
private CustomUserDetailsService userDetailService;
.....
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
userDetailService = applicationContext.getBean(CustomUserDetailsService.class);
}
}
This is the overriden configure
method in WebSecurityConfigurerAdapter
, where login filter comes in to the play:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.and()
.authorizeRequests()
.antMatchers("/signup").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.logout().logoutUrl("/logout").logoutSuccessHandler(logoutHandler).logoutSuccessUrl("/login").invalidateHttpSession(true)
.and()
// We filter the api/signup requests
.addFilterBefore(
new JWTSignupFilter("/signup", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// 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(userDetailsServiceBean()),
UsernamePasswordAuthenticationFilter.class);
}