将自定义UserDetailsS​​ervice自动装配到AbstractAuthenticationProcessingFilter中

时间:2017-05-10 02:29:31

标签: java spring

我有一个自定义UserDetailsS​​ervice:

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");
    }

}

我有一个注册过滤器(处理创建新用户)并扩展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);
    }
}

当执行到达userDetailService.loadUserByUsername时,我得到空指针异常,这意味着自动装配不起作用。

我尝试按照以下方式实施ApplicationContextAware,但它仍然是Null。我还用JWTSignupFilter注释了@Service,但它也没有用。知道如何解决这个问题吗?

public class JWTSignupFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {

    private CustomUserDetailsService userDetailService;

    .....

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        userDetailService = applicationContext.getBean(CustomUserDetailsService.class);     
    }
}

这是configure中的覆盖WebSecurityConfigurerAdapter方法,其中登录过滤器进入游戏:

@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);
} 

1 个答案:

答案 0 :(得分:-1)

试试这个:

将以下代码添加到配置文件中:

    @Bean
    public JWTSignupFilter jWTSignupFilter() throws Exception {
        return new JWTSignupFilter("/login", authenticationManager());
    }

将以下行添加到WebSecurityConfigurerAdapter扩展类

@Autowired 
JWTLoginFilter jWTSignupFilter

并替换

.addFilterBefore(
            new JWTLoginFilter("/login", authenticationManager()),
            UsernamePasswordAuthenticationFilter.class)

.addFilterBefore(
            jWTSignupFilter,
            UsernamePasswordAuthenticationFilter.class)

更新

您的WebSecurityConfigurerAdapter扩展类应该如下所示:

public Class CustomConfigurationClass extends WebSecurityConfigurerAdapter{
  @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(
                    jWTSignupFilter(),
                    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);
    } 

    @Bean
    public JWTSignupFilter jWTSignupFilter() throws Exception {
        return new JWTSignupFilter("/signup", authenticationManager());
    }
}