Spring Security getAuthenticationManager() 在自定义过滤器中返回 null
Posted
技术标签:
【中文标题】Spring Security getAuthenticationManager() 在自定义过滤器中返回 null【英文标题】:Spring Security getAuthenticationManager() returns null within custom filter 【发布时间】:2019-01-29 21:21:54 【问题描述】:我正在尝试在 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);
【问题讨论】:
如果在构造函数中添加setAuthenticationManager(new NoOpAuthenticationManager());
会怎样?
我认为 OP 希望他的 authenticate
获得荣誉。
添加了一个答案,希望不会太密集
【参考方案1】:
为什么您会看到 NullPointerException
您看到的是NullPointerException
,因为您没有将AuthenticationManager
连接到您的过滤器中。根据AbstractAuthenticationProcessingFilter
的javadocs@
过滤器要求您设置 authenticationManager 属性。需要一个 AuthenticationManager 来处理实现类创建的身份验证请求令牌
在这种情况下,我确实对为什么authenticationManager
没有为这个抽象过滤器的构造函数参数进行切割而摸不着头脑。我建议在您的构造函数中为您的自定义过滤器强制执行此操作。
public MyAuthenticationFilter(AuthenticationManager authenticationManager)
super(new AntPathRequestMatcher("/login", "POST"));
this.setAuthenticationManager(authenticationManager);
AuthenticationManager 或 AuthenticationProvider
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(myAuthenticationProvider);
AuthenticationManagerBuilder
将创建一个ProviderManager (an AuthenticationManager)
。
ProviderManager
是AuthenticationProvider
的集合,并且将尝试使用它管理的每个AuthenticationProvider
来authenticate()
。 (这就是public boolean supports(Class<?> authentication)
在AuthenticationProvider
合约中极其重要的地方)
在您的配置中,您创建了一个 ProviderManager
,其中仅包含您的自定义 Authentication Provider
酷。现在我的 AuthenticationManager 在哪里?
WebSecurityConfigurerAdapter
中的this.authenticationManager()
可以抓取configure()
方法构建的AuthenticationManager
@Bean
public AuthenticationManager authenticationManager throws Exception()
this.authenticationManager();
建议
创建您自己的 ProviderManager
确实有其好处,因为它是明确的并且在您的控制范围内。
@Bean
public AuthenticationManager authenticationManager()
return new ProviderManager(Arrays.asList(myAuthenticationProvider));
这将使您可以灵活地放置 AuthenticationManager
bean 并避免:
this.authenticationManager()
而使选中的 Exception
冒泡
将所有内容放在一起
...
public class AppConfig extends WebSecurityConfigurerAdapter
@Autowired
MyAuthenticationProvider myAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception
http.addFilterBefore(new MyAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class)
...
@Bean
public AuthenticationManager authenticationManager()
return new ProviderManager(Arrays.asList(myAuthenticationProvider));
【讨论】:
附加参考点:AuthenticationManager vs AuthenticationProvider 非常感谢!我在阅读文档时显然没有给予足够的关注,但您的回答可能仍然是必要的,因为我不知道将所有内容放在一起的正确位置。正如我在文档中看到的,ProviderManager 是 AuthenticationManager 的唯一实现;我的示例编写我自己的 AuthenticationManager 实现是否有意义,还是相当不寻常?顺便说一句,我总是感谢您写的其他建议;它有助于建立更好的上下文知识,因此值得称赞。 考虑到您只有一个AuthenticationProvider
,您可以选择提供一个AuthenticationManager 的实现。 ProviderManager
是通过不同的策略来工作
我明白了,不过似乎没有太多必要;坦克你!【参考方案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;
并用
修改配置方法http.addFilterBefore(myAuthenticationFilter(), BasicAuthenticationFilter.class).
...
【讨论】:
以上是关于Spring Security getAuthenticationManager() 在自定义过滤器中返回 null的主要内容,如果未能解决你的问题,请参考以下文章
Spring mvc / security:从spring security中排除登录页面
Spring Security:2.4 Getting Spring Security
没有 JSP 的 Spring Security /j_spring_security_check