【问题标题】:jsf spring security session timeout viewExpiredExceptionjsf spring安全会话超时viewExpiredException
【发布时间】:2012-02-21 21:50:56
【问题描述】:

我在使用 JSF 的 Spring Security 中的超时存在以下问题:

我已经自定义了会话管理过滤器,以便用户被重定向到 invalidSessionUrl,只要请求的页面是安全的(即,如果它只允许经过身份验证的用户)。我放入 Spring Security 提供的会话管理过滤器的自定义代码是:

if (invalidSessionUrl != null) {
     String pagSolicitada = UtilSpringSecurity.extraerPagina(request);
     if ( UtilSpringSecurity.paginaAutenticada(pagSolicitada ) ) {
          request.getSession();
          redirectStrategy.sendRedirect(request, response, invalidSessionUrl);
          return;
     }
     //the requested page doesn't require the user to be authenticated
     //so i just skip this filter and continue with the filter chain
     chain.doFilter(request, response);
     return;
}

方法“UtilSpringSecurity.extraerPagina(request)”以这种方式返回请求的页面:

public static String extraerPagina (HttpServletRequest request) {
     String uri = request.getRequestURI().toLowerCase();
     String cPath = request.getContextPath().toLowerCase();
     // uri = cPath + pagina
     int longCPath = cPath.length();
     String pagina = uri.substring(longCPath);
     return pagina;
}

如果参数是需要对用户进行身份验证的页面,则方法“UtilSpringSecurity.paginaAutenticada(pagSolicitada)”返回 true(考虑到我的 xml 安全配置文件的拦截 url 元素,我使用 IF 进行检查属性为access="isAuthenticated()"):

public static boolean paginaAutenticada (String pagina) {

     if (pagina.startsWith("/faces/paginas/administracion/") || pagina.startsWith("/faces/paginas/barco/") ) {
          return true;
     }
     return false;
}

此解决方案有效,但只有一个问题:

如果我让浏览器在页面上保持空闲直到会话超时到期,然后我请求同一页面,那么我会收到“viewExpiredException”。这是因为过滤器运行良好,它绕过了对 invalidSessionUrl 的重定向,但是由于会话无论如何都过期了,然后我尝试重新呈现同一页面时遇到该异常。

如果我在会话超时过期时请求任何其他不安全的页面,它运行良好,它会正确重定向到页面并且我没有收到 viewExpiredException。

有人知道怎么解决吗?

提前谢谢你。

【问题讨论】:

  • it bypassed the redirection to the invalidSessionUrl, but as the session expired anyway, then I get that exception trying to re-render the same page. 我不明白这是什么意思。你是说当你重新渲染 invalidSessionUrl 时你会得到一个 ViewExpiredException 吗?
  • 您为什么要编写自己的会话管理过滤器? Spring security 为您提供了开箱即用的功能。只需将以下内容添加到您的 Spring xml 配置 <http auto-config="true" ...> ... <session-management invalid-session-url="/login.xhtml"></session-management></http>
  • 回答您的第一条评论:it bypassed the redirection to the invalidSessionUrl, but as the session expired anyway, then I get that exception trying to re-render the same page。我的意思是当我重新渲染超时发生时浏览器显示的不安全页面时,我得到了“viewExpiredException”。发生这种情况是因为 JSF 无法构建页面的视图,因为会话已过期。 Spring Security 跳过了会话管理过滤器,因为页面不安全(这没关系),但是当 JSF 尝试重新渲染页面时,它会抛出异常。
  • 回答您的第二条评论:Spring Security 没有提供我想要的开箱即用功能。我想跳过不安全的请求页面的会话管理过滤器。默认过滤器没有实现这一点,也不能通过 xml 配置。这就是我编写自己的过滤器的原因,它与默认过滤器相同,但添加了检查以查看请求的页面是否安全。如果它不安全,我会跳过过滤器,以免被重定向到 invalidSessionUrl。这工作正常。

标签: jsf redirect spring-security timeout viewexpiredexception


【解决方案1】:

Spring 安全性应该让您匿名访问未经身份验证的用户的页面集。下面是我的 XML 配置的摘录,说明了我是如何实现这一点的。

<http auto-config="true" access-denied-page="/unauthorized.xhtml" >
    <intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
    <intercept-url pattern="/app/**" access="ROLE_USER,ROLE_ADMIN" />
    <intercept-url pattern="/*.xhtml" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <form-login login-page="/login.xhtml" login-processing-url="/j_spring_security_check"
        authentication-success-handler-ref="authenticationSuccessBean"
        authentication-failure-handler-ref="authenticationFailureBean"  />
    <session-management invalid-session-url="/login.xhtml" >
    </session-management>
</http>

我基本上使用intercept-url 标签来声明某些相对上下文中的页面只能由以下角色访问。您可以看到 Web 应用程序默认上下文中的所有页面都可供匿名用户使用。如果用户未经授权查看该页面,则他们将被重定向到access-denied-page

唯一的问题是您的 User bean 必须实现 UserDetails 接口,并且有一个属性可以返回实现 GrantedAuthority 接口的角色 bean。 Spring 将寻找 UserDetails 以具有 GrantedAuthority 属性来确定角色是什么。如果此用户不存在、未经身份验证或未知,则默认为匿名角色。

【讨论】:

  • 我知道你在说什么,但这不是我要找的。参考您的场景,如果会话超时时,任何用户(无论是否经过身份验证)都将被会话管理过滤器重定向到无效会话 URL,如果他们请求具有访问属性“IS_AUTHENTICATED_ANONYMOUSLY”的页面(即任何页面谁匹配模式“/ * .xhtml”并且不在管理员或应用程序目录中)。但我想要的不是在这种情况下被重定向到无效会话 url,只是显示我请求的页面,好像会话没有超时(即在这种情况下不应用会话管理过滤器)
【解决方案2】:

终于解决了。这是一个 JSF 问题,与 Spring Security 无关。

我已经通过这种方式覆盖了 jsf 的 restoreView 方法:

@Override
public UIViewRoot restoreView(FacesContext facesContext, String viewId) {
     UIViewRoot root = wrapped.restoreView(facesContext, viewId);
     if(root == null) {
          root = createView(facesContext, viewId);
     }
     return root;
}

现在的问题是,如果页面有参数,当我发布到最近创建的视图时,我会丢失它们,但这是另一个处理 JSF 的不同问题(PRG 模式)。

【讨论】:

    猜你喜欢
    • 2014-11-24
    • 2015-08-05
    • 2012-06-27
    • 2014-07-17
    • 2023-03-31
    • 2015-02-11
    • 1970-01-01
    • 2014-09-04
    相关资源
    最近更新 更多