Spring Security getAuthenticationManager()在自定义过滤器中返回null

时间:2018-08-23 13:19:30

标签: java spring spring-security

我正在尝试在Spring中实现一个非常简单的自定义身份验证过程示例,以更好地理解该概念。

我以为我现在已经准备就绪,但是发送一个请求以测试我实现的结果会导致NullPointerException异常,该异常可以追溯到 this.getAuthenticationManager()在我的自定义过滤器中返回null。但是我不明白为什么。不幸的是,现有的非常相似的问题并没有真正帮助我。因此,我将感谢您的帮助;这是我认为最相关的课程,请随时询问是否需要更多课程。

MyAuthenticationFilter (基于UsernamePasswordAuthenticationFilter的源代码),此行的最后一行发生错误:

public class MyAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public MyAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException(
                        "Authentication method not supported: " + request.getMethod());
            }

            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String secondSecret = request.getParameter("secondSecret");

            if (username == null) {
                username = "";
            }

            if (password == null) {
                password = "";
            }

            username = username.trim();

            MyAuthenticationToken authRequest = new MyAuthenticationToken(username, new MyCredentials(password, secondSecret));

            return this.getAuthenticationManager().authenticate(authRequest);
    }
}

我的配置类:

@Configuration
@EnableWebSecurity
@EnableWebMvc
@ComponentScan
public class AppConfig extends WebSecurityConfigurerAdapter
{
    @Autowired
    MyAuthenticationProvider myAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(myAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.addFilterBefore(new MyAuthenticationFilter(), BasicAuthenticationFilter.class)
                .authorizeRequests().antMatchers("/**")
                    .hasAnyRole()
                    .anyRequest()
                    .authenticated()
                    .and()
                .csrf().disable();
    }

    @Bean
    public ViewResolver viewResolver()
    {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

MyAuthenticationProvider

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MyAuthenticationToken myAuthenticationToken = (MyAuthenticationToken) authentication;
        MyCredentials credentials = (MyCredentials) myAuthenticationToken.getCredentials();
        if (credentials.getPassword().equals("sesamOeffneDich") && credentials.getSecondSecret().equals(MyAuthenticationToken.SECOND_SECRET)){
            myAuthenticationToken.setAuthenticated(true);
            return myAuthenticationToken;
        }else{
            throw new BadCredentialsException("Bad credentials supplied!");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return MyAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

2 个答案:

答案 0 :(得分:2)

您应该将身份验证管理器设置为过滤器。 您可以通过将此方法添加到配置类

 @Bean 
    public MyAuthenticationFilter myAuthenticationFilter() {
        MyAuthenticationFilter res = new MyAuthenticationFilter();
        try {
            res.setAuthenticationManager(authenticationManagerBean());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return res;
    }

并使用

修改configure方法

http.addFilterBefore(myAuthenticationFilter(), BasicAuthenticationFilter.class). ...

答案 1 :(得分:1)

为什么看到NullPointerException

您看到一个NullPointerException,因为您的过滤器中没有连接AuthenticationManager。根据{{​​1}}

的javadocs
  

过滤器要求您设置authenticationManager属性。需要AuthenticationManager来处理通过实现类创建的身份验证请求令牌

在这种情况下,我确实为AbstractAuthenticationProcessingFilter为何没有为该抽象过滤器的构造函数自变量做过准备而scratch之以鼻。我建议在您的自定义过滤器的构造函数中强制执行此操作。

authenticationManager

AuthenticationManager或AuthenticationProvider

public MyAuthenticationFilter(AuthenticationManager authenticationManager) {
    super(new AntPathRequestMatcher("/login", "POST"));
    this.setAuthenticationManager(authenticationManager);
}

@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(myAuthenticationProvider); } 将创建一个AuthenticationManagerBuilder

ProviderManager (an AuthenticationManager)ProviderManager的集合,将尝试与它管理的每个AuthenticationProvider一起authenticate()。 (这是AuthenticationProviderpublic boolean supports(Class<?> authentication)合同中极为重要的地方)

在您的配置中,您已经创建了一个AuthenticationProvider,其中仅包含您的自定义ProviderManager

酷。现在我的AuthenticationManager在哪里?

可以通过Authentication Provider中的AuthenticationManager抢夺通过configure()方法构建的this.authenticationManager()

WebSecurityConfigurerAdapter

建议

创建自己的@Bean public AuthenticationManager authenticationManager throws Exception() { this.authenticationManager(); } 确实有好处,因为它很明显,而且在您的控制范围之内。

ProviderManager

这将使您灵活地放置@Bean public AuthenticationManager authenticationManager() { return new ProviderManager(Arrays.asList(myAuthenticationProvider)); } bean,并避免:

  • bean配置中潜在的循环依赖问题
  • 由于调用AuthenticationManager而使选中的Exception冒泡

将它们放在一起

this.authenticationManager()