java - AuthenticationManager 在我的自定义过滤器中为空
问题描述
我的自定义过滤器基于UsernamePasswordAuthenticationFilter
需要,AuthenticationManager
但每次我调用该方法attemptAuthentication()
时,编译都会在此处失败:
Authentication auth2 = this.getAuthenticationManager().authenticate(authRequest);
为AuthenticationManager
空:
java.lang.NullPointerException: null
at app.shellx.security.CustomUsernamePasswordAuthenticationFilter.attemptAuthentication(CustomUsernamePasswordAuthenticationFilter.java:75) ~[classes/:na]
网络安全配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Autowired
private JwtTokenFilter jwtTokenFilter;
@Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.cors().and()
.csrf().disable()
.authorizeRequests() // .antMatchers("/**")
.antMatchers("/login/**", "/register/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
//.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
.addFilterAt(new CustomUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginPage("http://localhost:4200/login")//.failureUrl("/login-error")
.loginProcessingUrl("/login")
.usernameParameter("email")
.successHandler(customAuthenticationSuccessHandler)
.and()
.logout()
.permitAll();
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider()); // AuthenticationProvider inserted into ProviderManager
}
@Bean
public CustomDaoAuthenticationProvider authenticationProvider() {
CustomDaoAuthenticationProvider authenticationProvider = new CustomDaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
authenticationProvider.setUserDetailsService(userService);
return authenticationProvider;
}
/*@Bean
public CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter() throws Exception {
return new CustomUsernamePasswordAuthenticationFilter(authenticationManager());
}*/
//@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
// Return the AuthenticationManager used by the configure(AuthenticationManagerBuilder auth) method
@Bean(name = "CustomAuthenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
System.out.println("Configuration of authenticationManagerBean");
return super.authenticationManagerBean();
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebConfig() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(
"http://localhost:4200")
.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS")
.allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
"Access-Control-Request-Headers", "Authorization", "Cache-Control",
"Access-Control-Allow-Origin")
.exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
.allowCredentials(true).maxAge(3600);
}
};
}
}
自定义过滤器
public class CustomUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
private boolean postOnly = true;
public CustomUsernamePasswordAuthenticationFilter() { // AuthenticationManager authenticationManager
super(new AntPathRequestMatcher("/login", "POST"));
//this.setAuthenticationManager(authenticationManager);
System.out.println("Constructor filter");
}
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
UsernamePasswordAuthenticationToken authRequest = null;
try {
authRequest = this.getUserNamePasswordAuthenticationToken(request);
} catch (IOException e) {
e.printStackTrace();
}
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
System.out.println("AVANT AUTHENTIFICATION : "+authRequest.getPrincipal() + " " + authRequest.getCredentials());
//this.setAuthenticationManager(authenticationManager);
Authentication auth2 = this.getAuthenticationManager().authenticate(authRequest);
System.out.println("APRES AUTHENTIFICATION : "+auth2.getPrincipal() + " " + auth2.getCredentials());
return auth2;
}
private UsernamePasswordAuthenticationToken getUserNamePasswordAuthenticationToken(HttpServletRequest request) throws IOException {
StringBuffer sb = new StringBuffer();
BufferedReader bufferedReader = null;
String content = "";
AuthReq sr = null;
try {
bufferedReader = request.getReader();
char[] charBuffer = new char[128];
int bytesRead;
while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 ) {
sb.append(charBuffer, 0, bytesRead);
}
content = sb.toString();
ObjectMapper objectMapper = new ObjectMapper();
try{
sr = objectMapper.readValue(content, AuthReq.class);
}catch(Throwable t){
throw new IOException(t.getMessage(), t);
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
System.out.println("email : "+sr.getEmail());
System.out.println("password : "+sr.getPassword());
return new UsernamePasswordAuthenticationToken(sr.getEmail(), sr.getPassword());
}
public static class AuthReq {
String email;
String password;
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
}
@Autowired
@Qualifier("CustomAuthenticationManager")
@Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
System.out.println("Setter custom filter");
super.setAuthenticationManager(authenticationManager);
}
我尝试了几种解决方案,例如:
如何在自定义过滤器中使用 Java 配置注入 AuthenticationManager
无法通过 @Autowired 将 AuthenticationManager 传递给自定义过滤器
Spring boot Security Config - 必须指定 authenticationManager
我最终选择了第一个,因为我认为AuthenticationManager
为项目提供一个CustomFilter
bean 比只使用一次的 bean 更有用。
顺便说一句,对您来说,实现这样的过滤器的最佳解决方案是什么(避免循环依赖,更好的维护......)?
解决方案
您CustomUsernamePasswordAuthenticationFilter
不是由 Spring 管理的(因为您直接创建了它),因此您的过滤器中没有 Spring 管理的依赖注入行为。这就是为什么AuthenticationManager
从未注入并且现在为空的原因。
假设你把你的暴露AuthenticationManager
为一个豆子......
您可以
Filter
通过@Bean
您的WebSecurityConfig
或者,您可以在
AuthenticationManager
创建过滤器对象时简单地将 传递给您的过滤器(通过其构造函数或设置器)。无需将过滤器公开为 bean。
推荐阅读
- c# - 如何清除 WPF 应用程序中的 Web 浏览器缓存 - 上下文存储?
- git - 在不打开管理用户的情况下设置 git SSH 服务器
- javascript - React javascript 通过 ID 获取值
- vue.js - 删除商店 Vuex 中的项目
- arrays - 在数组中添加和显示新对象的函数
- python - 文件中数字总和的脚本,这些数字用文本和特殊字符不带空格写入
- reactjs - React Typescript 解决方案 - 关闭当前弹出窗口并打开另一个弹出窗口并选择某个导航选项卡?
- javascript - 编辑功能的问题会覆盖本地存储并引发错误
- linux - 中间分区是 BIOS Boot 时如何调整分区大小?
- r - 在R中按经度和纬度合并数据