java - 尝试使用 AbstractPreAuthenticatedProcessingFilter 实现访问特定 URL 后出现 IllegalStateException
问题描述
我们扩展了 AbstractPreAuthenticatedProcessingFilter 来验证 shibboleth 用户,它没有什么特别的,只是从特定的请求属性中获取用户名并返回一个 PreAuthenticatedAuthenticationToken。
如果我们访问应用程序的根上下文,它可以正常工作,但如果我们在应用程序中请求特定的 URL,我们会得到“java.lang.IllegalStateException:响应已提交”。
在 SecurityConfig 我们有:
@Override
protected void configure(final HttpSecurity http) throws SecurityException {
try {
http.authorizeRequests().antMatchers("/favicon.ico", "/resources/**", "/signin**").permitAll()
.anyRequest().authenticated().and().formLogin().loginPage("/signin").permitAll()
.failureUrl("/signin?error=1").successHandler(new CustomAuthenticationSuccessHandler())
.loginProcessingUrl("/authenticate").and().sessionManagement().invalidSessionUrl("/signin")
.and().exceptionHandling().accessDeniedHandler(new AccessDeniedHandler()).and().headers()
.frameOptions().disable();
http.addFilterBefore(
new ShibbolethPreAuthenticatedProcessingFilter(new ShibbolethAuthenticationManager(),
new CustomAuthenticationSuccessHandler()),
AbstractPreAuthenticatedProcessingFilter.class);
http.logout().logoutUrl("/logout")
.logoutSuccessUrl(environment.getProperty(Constantes.CT_SHIBBOLETH_LOGOUT_URL))
.clearAuthentication(true).invalidateHttpSession(true);
} catch (final Exception e) {
throw new SecurityException(e);
}
}
ShibbolethAuthenticationManager 实现 AuthenticationManager 并且只是将 UserDetails 和 GrantedAuthorities 加载到 PreAuthenticatedAuthenticationToken
CustomAuthenticationSuccessHandler 扩展 SavedRequestAwareAuthenticationSuccessHandler 并将用户语言加载到 LocaleProvider 并将当前许可证详细信息加载到会话中。
如果我们在应用程序中请求“/”,它需要我们:
@ResponseStatus(HttpStatus.MOVED_PERMANENTLY)
@RequestMapping("/")
public String index(HttpServletRequest httpRequest, HttpSession session, Authentication auth) {
if (auth.getAuthorities().contains(new SimpleGrantedAuthority(Constants.CONTROL_PANEL_PERMISSION))) {
return "redirect:/controlpanel/dashboard";
} else if (auth.getAuthorities().contains(new SimpleGrantedAuthority(Constants.CONFIG_PERMISSION)))
{
return "redirect:/config";
} else {
return "redirect:/userpage";
}
}
我不知道为什么这些重定向有效,但是当我们请求另一个 URL 时,例如,如果我们请求直接转到 /controlpanel/dashboard,我们会收到错误消息。
@RequestMapping("/controlpanel/dashboard")
public String dashboard(Model model, HttpServletRequest httpRequest, HttpSession session,
@RequestParam(name = "comite", defaultValue = "-1") Long comite,
@RequestParam(required = false) final Boolean tasksToDo) {
// This method does nothing but add things to the model object, such as:
model.addAttribute("tasks", tasksToDo);
// and then it takes the user to the view page
return "cuadromando/dashboard";
}
编辑:堆栈跟踪:
2020-12-02 14:14:07|ERROR|NA|01.10.00|http-nio-8080-exec-2|java.lang.IllegalStateException: No puedo reenviar después de que la respuesta se haya llevado a cabo.
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:323)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.sitemesh.webapp.WebAppContext.dispatch(WebAppContext.java:182)
at org.sitemesh.webapp.WebAppContext.decorate(WebAppContext.java:157)
at org.sitemesh.BaseSiteMeshContext.decorate(BaseSiteMeshContext.java:39)
at org.sitemesh.webapp.SiteMeshFilter.postProcess(SiteMeshFilter.java:83)
at org.sitemesh.webapp.contentfilter.ContentBufferingFilter.bufferAndPostProcess(ContentBufferingFilter.java:175)
at org.sitemesh.webapp.contentfilter.ContentBufferingFilter.doFilter(ContentBufferingFilter.java:126)
at org.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:120)
at org.sitemesh.config.ConfigurableSiteMeshFilter.doFilter(ConfigurableSiteMeshFilter.java:163)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:121)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at es.bahiasoftware.meet.web.filter.RefererManagerFilter.doFilter(RefererManagerFilter.java:49)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:122)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:178)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
解决方案
最后我通过实现 AuthenticationSuccessHandler 而不是扩展 SavedRequestAwareAuthenticationSuccessHandler 来解决它:
CustomSuccessHandler implements AuthenticationSuccessHandler
所以我摆脱了提交的响应,因为 SavedRequestAwareAuthenticationSuccessHandler 和 SimpleUrlAuthenticationSuccessHandler 都调用了 getRedirectStrategy().sendRedirect(request, response, targetUrl); 所以他们在我们可以做我们需要的实际重定向之前提交了响应。
推荐阅读
- meteor - Meteor App:ReferenceError:未定义包
- doctrine-orm - Doctrine ORM 如何将我的对象的 UPDATE 保存到数据库(相当于 SQL UPDATE 查询)
- python - Spyder:检查失败:PyBfloat16_Type.tp_base != nullptr 启动内核时出错
- php - 新行 \n 奇怪的输出并且不工作 PHP 7.1
- python - 使用列表中的 kwargs 多次调用函数 [python]
- c# - Razor 没有将我的“选定”值写入页面
- matlab - MATLAB Workspace 给了我不同的值
- mongodb - MongoDB:名称不同但含义相同的字段
- c++ - Qt C++ 括号匹配和突出显示当前行功能不能一起工作
- xcode - Xcode 调试中的 stl(libcxx) 渲染器