发生超时后调用 Servlet 方法(控制器)时,Spring Security 3.1 重定向到登录不起作用

Posted

技术标签:

【中文标题】发生超时后调用 Servlet 方法(控制器)时,Spring Security 3.1 重定向到登录不起作用【英文标题】:Spring Security 3.1 redirect to login doesn't work when a call a Servlet Method (Controller) after Timeout occurs 【发布时间】:2014-06-11 18:36:54 【问题描述】:

问题类似: Spring Security 3.1 redirect to login doesn't work

我将 Spring 3.1 与 Spring Mvc 和 Spring Security 一起使用。

这里,app-security-config。

<security:http  auto-config="true" use-expressions="true">
    <security:form-login login-page="/login.jsp" 
                    login-processing-url="/j_spring_security_check" 
                    default-target-url="/pages/index.jsp"
                    always-use-default-target="true"
                    authentication-failure-url="/login.jsp?login_error=1"/>
                    <security:access-denied-handler ref="accessDeniedHandler"/>

    <!--  Session Invalida-->
    <security:logout invalidate-session="true" logout-success-url="/login.jsp" delete-cookies="JSESSIONID" />

    <!--  Interceptadores -->
    <!-- security:intercept-url pattern="/expire.jsp*" filters="none"/-->
    <!-- security:intercept-url pattern="/login.jsp*" access="ROLE_ANONYMOUS" requires-channel="https"/-->

    <security:intercept-url pattern="/expire.jsp" access="permitAll" />
    <security:intercept-url pattern="/AccessDenied.jsp*" access="permitAll" />
    <security:intercept-url pattern="/scripts/*" access="permitAll" />
    <security:intercept-url pattern="/styles/*" access="permitAll" />
    <security:intercept-url pattern="/images/*" access="permitAll" />
    <security:intercept-url pattern="/login.jsp" access="permitAll" requires-channel="https"/>
    <security:intercept-url pattern="/pages/**" access="hasAnyRole($role.autenticated)"  requires-channel="https"/>
    <security:http-basic/>

    <!--  Establece maximas sesiones para un usuarios -->
    <security:session-management session-fixation-protection="none" >
       <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
    </security:session-management>         

    <!--  Establece maximas sesiones para un usuarios -->
    <!-- security:session-management invalid-session-url="/expire.jsp"  session-fixation-protection="none" >
       <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/expire.jsp"/>
    </security:session-management-->    

    <!-- security:session-management invalid-session-url="/login.jsp?login_error=2" session-authentication-error-url="/login.jsp?login_error=3" session-fixation-protection="none" >
       <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.jsp?login_error=4"/>
    </security:session-management-->   

    <security:port-mappings>
        <security:port-mapping http='8080' https="8443"/>
    </security:port-mappings>

</security:http>


<beans:bean id="accessDeniedHandler" class="ar.com.firstdata.upploader.web.mvc.controller.AccessDeniedController">
    <beans:property name="accessDeniedUrl" value="/AccessDenied.jsp"> </beans:property>
</beans:bean> 

一个 web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:META-INF/spring/*-config.xml</param-value>
</context-param>

<jsp-config>
    <taglib>
        <taglib-uri>sitemesh-page</taglib-uri>
        <taglib-location>/tld/sitemesh-page.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>sitemesh-decorator</taglib-uri>
        <taglib-location>/tld/sitemesh-decorator.tld</taglib-location>
    </taglib>

    <taglib>
        <taglib-uri>/spring</taglib-uri>
        <taglib-location>/META-INF/spring.tld</taglib-location>
    </taglib>
</jsp-config>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

<!-- SiteMesh -->
<filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>*.htm</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<session-config>
    <session-timeout>1</session-timeout>
</session-config>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.app</url-pattern>
</servlet-mapping>

<welcome-file-list>
    <welcome-file>login.jsp</welcome-file>
</welcome-file-list>

该问题仅在尝试访问结束调用控制器方法的某些操作时发生:

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/pages/findConfData.app">configurationController</prop>
            <prop key="/pages/readLoadXML.app">configurationController</prop>
            <prop key="/pages/addElementToList.app">configurationController</prop>
            <prop key="/pages/eraseElementToList.app">configurationController</prop>
            <prop key="/pages/persistXMLfiletransfer.app">configurationController</prop>
            <prop key="/pages/findLoggedUser.app">configurationController</prop>
        </props>            
    </property>
</bean>

正如我所说,该行为类似于@spauny 披露的行为,在日志中出现:“访问被拒绝(用户是匿名的);重定向到身份验证入口点”,在 AccessDeniedException 之后没有任何反应,。 ..

这是一种情况: 如果我花费在 web.xml 中列出的时间

<session-config>
    <session-timeout>1</session-timeout>
</session-config>

我调用了一个受限页面(在“/pages/**”下)将我重定向到登录页面...... 但是当尝试调用一些最终调用控制器方法的操作时 - 假设删除列表中的一行-

<prop key="/pages/eraseElementToList.app">configurationController</prop>

@RequestMapping(method = RequestMethod.POST)
public final ModelAndView eraseElementToList(HttpServletRequest request,    
HttpServletResponse response) throws Exception 

我只是在日志中收到一个 ActionDenied 异常,仅此而已...没有将我重定向到登录页面。

更新 1 04/25 19:43:27 调试 hannel.ChannelProcessingFilter - 请求:FilterInvocation:URL:/pages/persistXMLfiletransfer.app;配置属性:[REQUIRES_SECURE_CHANNEL] 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中第 12 位的第 2 位;触发过滤器:'ConcurrentSessionFilter' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中第 12 位的第 3 位;触发过滤器:'SecurityContextPersistenceFilter' 04/25 19:43:27 调试 ssionSecurityContextRepository - HttpSession 返回了 SPRING_SECURITY_CONTEXT 的空对象 04/25 19:43:27 调试 ssionSecurityContextRepository - HttpSession 没有可用的 SecurityContext:org.apache.catalina.session.StandardSessionFacade@521f809b。将创建一个新的。 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中第 12 位的第 4 位;触发过滤器:'LogoutFilter' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中 12 位的第 5 位;触发过滤器:'UsernamePasswordAuthenticationFilter' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中 12 位的第 6 位;触发过滤器:'BasicAuthenticationFilter' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中第 12 位的第 7 位;触发过滤器:'RequestCacheAwareFilter' 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - pathInfo: 都为空(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - queryString: 都为空(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - requestURI: arg1=/UppAudioFilesWebApp/pages/persistXMLfiletransfer.app; arg2=/UppAudioFilesWebApp/pages/persistXMLfiletransfer.app(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - serverPort: arg1=8443; arg2=8443(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - requestURL: arg1=/UppAudioFilesWebApp/pages/persistXMLfiletransfer.app; arg2=/UppAudioFilesWebApp/pages/persistXMLfiletransfer.app(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - 方案:arg1=https; arg2=https(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - serverName: arg1=localhst; arg2=localhst(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - contextPath: arg1=/UppAudioFilesWebApp; arg2=/UppAudioFilesWebApp(属性等于) 04/25 19:43:27 调试 vedrequest.DefaultSavedRequest - servletPath: arg1=/pages/persistXMLfiletransfer.app; arg2=/pages/persistXMLfiletransfer.app(属性等于) 04/25 19:43:27 调试 equest.HttpSessionRequestCache - 如果存在,则从会话中删除 DefaultSavedRequest 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中 12 位的第 8 位;触发过滤器:'SecurityContextHolderAwareRequestFilter' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中 12 位的第 9 位;触发过滤器:'AnonymousAuthenticationFilter' 04/25 19:43:27 DEBUG .AnonymousAuthenticationFilter - 使用匿名令牌填充 SecurityContextHolder:'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc:主体:anonymousUser;凭证:[受保护];已认证:真实;详细信息:org.springframework.security.web.authentication.WebAuthenticationDetails@b364:RemoteIpAddress:0:0:0:0:0:0:0:1;会话ID:63C5BB1C1CD8981AAF23D71C5521FB9B;授予权限:ROLE_ANONYMOUS' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中第 12 位的第 10 位;触发过滤器:'SessionManagementFilter' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中第 12 位的第 11 位;触发过滤器:'ExceptionTranslationFilter' 04/25 19:43:27 DEBUG .security.web.FilterChainProxy - /pages/persistXMLfiletransfer.app 位于附加过滤器链中第 12 位的第 12 位;触发过滤器:'FilterSecurityInterceptor' 04/25 19:43:27 调试 web.util.AntPathRequestMatcher - 检查请求的匹配:'/pages/persistxmlfiletransfer.app';反对'/expire.jsp' 04/25 19:43:27 调试 web.util.AntPathRequestMatcher - 检查请求的匹配:'/pages/persistxmlfiletransfer.app';反对'/accessdenied.jsp*' 04/25 19:43:27 调试 web.util.AntPathRequestMatcher - 检查请求的匹配:'/pages/persistxmlfiletransfer.app';反对 '/scripts/' 04/25 19:43:27 调试 web.util.AntPathRequestMatcher - 检查请求的匹配:'/pages/persistxmlfiletransfer.app';反对'/styles/' 04/25 19:43:27 调试 web.util.AntPathRequestMatcher - 检查请求的匹配:'/pages/persistxmlfiletransfer.app';反对 '/images/*' 04/25 19:43:27 调试 web.util.AntPathRequestMatcher - 检查请求的匹配:'/pages/persistxmlfiletransfer.app';反对'/login.jsp' 04/25 19:43:27 调试 web.util.AntPathRequestMatcher - 检查请求的匹配:'/pages/persistxmlfiletransfer.app';反对'/pages/**' 04/25 19:43:27 调试 cept.FilterSecurityInterceptor - 安全对象:FilterInvocation:URL:/pages/persistXMLfiletransfer.app;属性:[hasAnyRole('ROLE_TOMCAT', 'ROLE_ADMNI')] 04/25 19:43:27 调试 cept.FilterSecurityInterceptor - 先前已验证:org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc:主体:anonymousUser;凭证:[受保护];已认证:真实;详细信息:org.springframework.security.web.authentication.WebAuthenticationDetails@b364:RemoteIpAddress:0:0:0:0:0:0:0:1;会话ID:63C5BB1C1CD8981AAF23D71C5521FB9B;授予权限:ROLE_ANONYMOUS 04/25 19:43:27 DEBUG y.access.vote.AffirmativeBased - 投票者:org.springframework.security.web.access.expression.WebExpressionVoter@1304ff98,返回:-1 04/25 19:43:27 DEBUG ess.ExceptionTranslationFilter - 访问被拒绝(用户是匿名的);重定向到身份验证入口点 org.springframework.security.access.AccessDeniedException:访问被拒绝 在 org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) 在 org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:205) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:114) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 在 org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 在 org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:101) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 在 org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)

【问题讨论】:

可能是浏览器的问题?非常感谢 你能把它清理一下,所以当你访问一个受限页面时它可以工作,但是当你输入控制器请求映射时它就不行了? 我更新了我的问题...谢谢! 【参考方案1】:

这里最可能的解释是您有一个 Spring ExceptionHandler,它捕获了 AccessDeniedException 并阻止 Spring Security 对其进行操作。如果您在某处使用安全注释,这是一个很常见的问题(尽管您在问题的任何地方都没有提到这一点)。

从堆栈跟踪中也应该清楚,它提到了 Spring Security 没有处理的异常(总是发布堆栈跟踪)。此外,请更仔细地重新检查日志以区分这两种情况。如果您看到“重定向到身份验证入口点”,则意味着 Spring Security 正在接收异常,您应该看到登录页面。如果使用异常处理程序,您将看不到这一点。

如果这是问题所在,您可以使您的 @ExceptionHandler 注释更加具体,以便它们不会捕获此异常,或者您可以创建一个特定的 @ExceptionHandler(AccessDeniedException.class) 并简单地在其中重新抛出异常。

【讨论】:

Luke,没有提到@ExceptionHandler,只是因为我没有使用它。我复制了一部分日志,更新我的问题!如您所见,它正在尝试调用: /pages/persistXMLfiletransfer.app 这是控制器的方法:@RequestMapping(method = RequestMethod.POST) public final ModelAndView persistXMLfiletransfer(HttpServletRequest request, HttpServletResponse response) throws Exception 但是,如TIMEOU(一分钟!)已完成,spring 尝试重定向到身份验证入口点,但异常并没有,我的浏览器没有任何反应。 异常正常。入口点应发送重定向到登录页面。您应该能够通过使用合适的 Web 开发人员插件或浏览器的默认工具在浏览器中调试请求来验证是否发生这种情况。我还会尝试禁用 https 并删除对它的引用,以确保不会导致问题。 卢克,你的 GAE 博客文章也有类似的问题。我无法让应用程序重定向到注册页面,因为 org.springframework.security.web.access.ExceptionTranslationFilter 捕获了一些东西并引发了 ACCESS DENIED 错误。我该如何处理?

以上是关于发生超时后调用 Servlet 方法(控制器)时,Spring Security 3.1 重定向到登录不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Servlet,jsp,jsp的9大内置对象

Grails Spring Security - 会话超时后重新登录时重新加载会话变量

JavaEE复习二

数据库异常后的SQL超时

[javaEE] Servlet中Session的使用

会话超时通知