Spring启动中的无限循环AuthenticationFilter

时间:2018-02-19 10:39:28

标签: spring rest authentication spring-boot jwt

我们最近将Java配置的spring应用程序转换为spring boot并且旧应用程序工作正常但是在将其转换为spring boot项目后,我们在JWT令牌保护的端点中遇到严重问题所有这些都创建了无穷无尽的循环并最终抛出StackOverflow例外。

以下是没有实际代码的整个JWT令牌文件管理器的非常抽象的示例,因为原始代码非常冗长,我觉得这对于擅长于春天的人来说已经足够了解。

public class TokenAuthenticationFilter extends UsernamePasswordAuthenticationFilter {



  public TokenAuthenticationFilter() {
    setAuthenticationManager(new AuthenticationManager() {
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            return null; // no different in the original code 
        }
    });
    setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler() {
        @Override
        protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
            String context = request.getContextPath();
            String fullURL = request.getRequestURI();
            String url = fullURL.substring(fullURL.indexOf(context) + context.length());
            return url;
        }

        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
            String url = determineTargetUrl(request, response);
            request.getRequestDispatcher(url).forward(request, response);
        }
    });
    setRequiresAuthenticationRequestMatcher(new RequestMatcher() {
        public boolean matches(HttpServletRequest request) {
            return getTokenRequest(request);
        }
    });
}


private boolean getTokenRequest(HttpServletRequest request) {
    String userAuthToken = request.getHeader("X-Auth-Token");
    return userAuthToken != null;
}


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

    List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>(1);
    roles.add(new SimpleGrantedAuthority("USER_ROLE"));
    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("imaa95@gmail.com", "", roles);
    return authRequest;
 }
}

基本上在实际的代码中,在attemptAuthentication方法中验证一旦完成,spring会调用onAuthenticationSuccess方法,在此基础上我们将请求转发给控制器的逻辑

request.getRequestDispatcher(url).forward(request, response);

我认为这是无限循环的原因,因为这会创建一个新的请求,将再次被同一个过滤器捕获,但奇怪的是这个确切的代码在以前的基于java的配置中没有任何问题,所以我们如果有人能够发现问题并为我们提供一种以最少的代码更改来解决问题的方法,那真的很高兴

这里要求的是安全配置

@Override
protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authenticationProvider(daoAuthenticationProvider())
            .authorizeRequests()
            .antMatchers("/", "/allData").permitAll()
            .anyRequest().authenticated()
            .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .formLogin().usernameParameter("email").passwordParameter("password")
                .successHandler(getLoginSuccessHandler())
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request,
                                                        HttpServletResponse response,
                                                        AuthenticationException e) throws IOException,
                            ServletException {
                        response.getWriter().write("Login Failed :(");
                    }
                })
            .and()
                .logout()
                    .logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) )
                    .logoutSuccessHandler( getLogoutSuccessHandler() )
                    .deleteCookies( "uc" )
                    .invalidateHttpSession( true )
                    .and()
            .exceptionHandling()
            .authenticationEntryPoint(getEntryPoint());

    http.addFilterBefore(new TokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

1 个答案:

答案 0 :(得分:0)

我怀疑由于登录页面也经过身份验证,请求会陷入无限循环。在您的配置中,尝试在loginPage之后立即放置permitAll()。

.formLogin().loginPage("/login").permitAll()

然后是其他配置。

修改 由于上述修复不起作用,我怀疑身份验证在2个身份验证提供程序之间卡住可能导致问题。你能尝试在令牌过滤器中注入daoAuthprovider吗?做到这一点的方法是: 删除配置:

authenticationProvider(daoAuthenticationProvider())

http.authenticationProvider(daoAuthenticationProvider())
            .authorizeRequests()

并修改以下配置:

http.addFilterBefore(new TokenAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);

daoauthProvider可以配置为:

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

在你的TokenAuthenticationFilter中,你可以这样做:

public TokenAuthenticationFilter(AuthenticationManager authManager) {       
        setAuthenticationManager(authManager);
    }

我建议根据我过去对问题的经验提出解决方案。我不确定它是否适用于您的情况。