我正在尝试在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);
}
}
答案 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}}
过滤器要求您设置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()
。 (这是AuthenticationProvider
在public 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,并避免:
AuthenticationManager
而使选中的Exception
冒泡将它们放在一起
this.authenticationManager()