Spring 具有自定义过滤器和多个身份验证提供程序的 REST 安全性 - 成功身份验证时未调用目标方法

Spring REST Security with Custom Filters and Multiple Authentication Providers - Target Method Not Called On Successful Authentication

我正在为 REST 服务实施 Spring 安全模块。它涉及 2 个自定义过滤器和 2 个自定义身份验证提供程序。该应用程序使用 Spring 4.1.5.RELEASE 和 Spring 安全 4.0.0.RELEASE。没有XML。 身份验证成功后,我的自定义 AuthenticationSuccessHandler 就可以正常调用了。在 onAuthenticationSuccess 方法内部,我只是简单地重构了原来的 URL 并转发了请求。但是请求永远不会到达 REST 服务。我没有收到任何错误,只有一个状态为 200 的空响应。我通过删除自定义过滤器进行了检查,服务正常调用。即使在调用成功处理程序之后我也无法弄清楚。为什么请求从未到达目标?请帮忙

WebSecurityConfigurerAdapter 实施:

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

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
    .anyRequest()
    .authenticated()
    .and()
    .exceptionHandling()
    .authenticationEntryPoint(restAuthenticationEntryPoint)
    .and()
    .sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
    .addFilterBefore(serviceRegistrationValidatingFilter,
    CustomUsernamePasswordAuthenticationFilter.class)
    .addFilter(authFilter);
}

AuthenticationEntryPoint 实施:

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request,
            HttpServletResponse response, AuthenticationException authException)
            throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                authException.getMessage());
    }
}

AuthenticationSuccessHandler 实施:

@Component
public class RestAuthenticationSuccessHandler extends
        SimpleUrlAuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {
        String path = Joiner.on("/")
                .join(request.getServletPath(), request.getPathInfo())
                .replaceAll("//", "/");
        request.getRequestDispatcher(path).forward(request, response);
        clearAuthenticationAttributes(request);
    }
}

显示创建的过滤器链的日志(为简洁起见,省略了包名称和哈希码)。我的过滤器在我希望的位置。

INFO: Creating filter chain: AnyRequestMatcher, [WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, ServiceRegistrationValidatingFilter, CustomUsernamePasswordAuthenticationFilter, RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, FilterSecurityInterceptor]

所以问题原来是使用 Spring MockMvc。我需要使用 forwardedUrl("forwardToUrl") 进行验证。正如我在上面发布的那样,实际的转发并没有发生。 content().string("expectedString") 也没有用,内容是空白的。

看来 MockMvc 旨在测试行为,而不是数据。

 mockMvc.perform(get("/form"))
     .andExpect(status().isOk())
     .andExpect(content().string("expectedString"))
     .andExpect(forwardedUrl("forwardToUrl"));