【问题标题】:StackOverflowError while using authenticationManager.authenticate() method使用 authenticationManager.authenticate() 方法时出现 StackOverflowError
【发布时间】:2022-11-03 18:54:37
【问题描述】:

我在使用authenticationManger.authenticate() 时收到StackOverflowError。我看到这里已经回答了问题:Why AuthenticationManager is throwing StackOverflowError?,但我没有扩展已弃用的WebSecurityConfigurerAdapter,所以我的配置如下所示:

@Configuration
@EnableWebSecurity
public class SecurityConfig{

    @Bean
    public UserDetailsService userDetailsService() {
        return new CustomUserDetailsService();
    }

    @Bean
    @Order(1)
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.httpBasic().disable().csrf().disable().sessionManagement()
                .and().authorizeRequests()
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated().and().csrf().disable();
        http
                .logout()
                .invalidateHttpSession(true)
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK));
        return http.build();
    }

    @Bean
    @Order(0)
    public SecurityFilterChain resources(HttpSecurity http) throws Exception {
        http.requestMatchers((matchers) -> matchers.antMatchers("*.bundle.*"))
                .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
                .requestCache().disable()
                .securityContext().disable()
                .sessionManagement().disable();

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

我仍然得到

2022-07-18 17:26:52.277 ERROR 12368 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause

java.lang.StackOverflowError: null
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
    at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
    at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
    at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
    at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]

*continues till stack overflow*

我在这里借用的AuthenticationManager bean 的当前版本(在评论部分):spring.io docs

我在控制器中使用AuthenticationManager 手动验证用户身份:

@CrossOrigin
@RestController
public class UserController {

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    CustomUserService userService;

    @Autowired
    JwtTokenProvider jwtTokenProvider;

    @PostMapping("/login")
    public ResponseEntity<Map<Object, Object>> login(@RequestBody CustomUserLoginDto userDto) {
        try {
            String email = userDto.getEmail();
            Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, userDto.getPassword()));
            SecurityContextHolder.getContext().setAuthentication(authentication);
            String token = jwtTokenProvider.createToken(email);
            Map<Object, Object> model = new HashMap<>();
            model.put("username", email);
            model.put("token", token);
            return ResponseEntity.ok(model);
        } catch (AuthenticationException e) {
            throw new BadCredentialsException("Invalid email/password supplied");
        }
    }

    @PostMapping("/register")
    public CustomUser register(@RequestBody CustomUserCreateDto userDto) {
        return userService.saveUser(userDto);
    }
}

我该如何解决这个问题?

【问题讨论】:

  • 我依稀记得从 WebSecurityConfigurerAdapter 转换时遇到了类似的情况。如果删除 AuthenticationManager bean 会发生什么?
  • @LeeGreiner,整个安全系统都没有,但我想在控制器中使用这个 bean,所以我必须定义它。如果有其他方法来定义它,我也想知道,谢谢
  • 为什么需要控制器中的AuthenticationManager?您能否描述请求并调试FilterChainProxy 并找到导致堆栈溢出的过滤器?
  • 在幕后是一个 AuthenticationManagerBuilder。我的猜测是 AuthenticationManager bean 在您的控制器中可用,但我不得不问您为什么在控制器中需要它。
  • @LeeGreiner 添加了相关信息,请参阅问题

标签: java spring-boot spring-security jwt


【解决方案1】:

最好用扩展 AbstractAuthenticationProcessingFilter 的自定义过滤器替换您的登录方法

public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    protected AuthenticationFilter() {
        super("/login");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        if (!request.getMethod().equalsIgnoreCase(HttpMethod.POST.name())) {
            return null;
        }

        // extract login and password
        return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(login, password));

    }

}

要访问AuthenticationManager,您应该使用自定义 DSL (Accessing the local AuthenticationManager)

public class CustomDsl extends AbstractHttpConfigurer<CustomDsl, HttpSecurity> {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
        http.addFilterAfter(authenticationFilter(authenticationManager), ConcurrentSessionFilter.class);
    }

    public AuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) {
        final AuthenticationFilter authenticationFilter = new AuthenticationFilter();
        authenticationFilter.setAuthenticationManager(authenticationManager);
        authenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
        authenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
        return authenticationFilter;
    }

    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new CustomAuthenticationSuccessHandler();
    }

    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new CustomAuthenticationFailureHandler();
    }

}

然后应用它

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    // ...
    http.apply(customDsl());
    return http.build();
}

并将其从您的配置中删除

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
    return authenticationConfiguration.getAuthenticationManager();
}

【讨论】:

    猜你喜欢
    • 2018-06-17
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多