JSF 2 + Spring 3 + Shiro - 会话超时不重定向到登录页面

Posted

技术标签:

【中文标题】JSF 2 + Spring 3 + Shiro - 会话超时不重定向到登录页面【英文标题】:JSF 2 + Spring 3 + Shiro - Session Timeout doesn't redirect to login page 【发布时间】:2012-08-19 10:04:04 【问题描述】:

我有这个 JSF 2.0/Spring 应用程序,它添加了 Apache Shiro,并且当用户单击命令按钮或触发 AJAX 请求时,会话超时后不会发生重定向。当他们刷新浏览器时它确实有效。这发生在所有浏览器中。这是我的 applicationContext.xml:

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/index.faces"/>
        <property name="filterChainDefinitions">
                <value>
                        /* = authc 
                </value>
        </property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="opacsRealm" />
</bean>

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

<bean id="sha512Matcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">

        <property name="hashAlgorithmName" value="SHA-256" />
        <property name="hashIterations" value="1024" />
</bean>



<bean id="opacsRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
        <property name="dataSource" ref="dataSource" />
        <property name="authenticationQuery" 
                value="select PASSWORD, SALT from SEC_USERS where NAME = ?" />
        <property name="userRolesQuery" 
                value="SELECT ROLE_NAME FROM SEC_USERS_ROLES WHERE USER_NAME = ?" />
        <property name="permissionsQuery" 
                value="SELECT permission FROM SEC_ROLES_PERMISSIONS WHERE ROLE_NAME = ?" />
        <property name="permissionsLookupEnabled" value="true" />
        <property name="saltStyle" value="COLUMN" />
        <property name="credentialsMatcher" ref="sha512Matcher"/>
</bean>

我在设置中做错了吗? web.xml 如下所示:

<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
  <!-- web.xml expects the session timeout in minutes: -->
  <session-timeout>1</session-timeout>
</session-config>

【问题讨论】:

只是为了好玩,我将 authc 更改为使用自定义 FormAuthenticationFilter 并覆盖 redirectToLogin 方法并添加回父类中的代码。没有变化,但我添加到方法中的日志语句确实打印了,所以重定向正在发生,但浏览器永远不会重定向,除非完成屏幕刷新。 我没有给你答案,但我可以告诉你,这很可能按设计工作。使用此配置,当会话超时时,authc 过滤器会将任何 ajax 请求重定向到登录页面。但是,为了让您的页面刷新到登录页面,javascript 需要解释 302 响应并刷新页面。最近在 Shiro 用户列表上讨论过这个问题,相信提问者找到了合适的解决方案:shiro-user.582556.n2.nabble.com/… 我刚刚读到了,谢谢。他没有回复他的解决方案,所以我会看看我是否可以从他的帖子中弄清楚。 【参考方案1】:

刚刚回复了你的邮件。正在发生的事情是重定向由浏览器在您的 Ajax 调用中无缝处理,因此 Shiro 确实重定向到登录页面,您的 Ajax 请求的最终结果是登录页面的 html 内容,这并不是您真正想要的!

解决此问题的要点是向您的 Ajax Api url 添加一个(自定义)Shiro 过滤器,以检查主题是否已通过身份验证,而不是重定向到登录,而是返回您的 Ajax 请求理解的响应以指示用户未登录。然后,客户端处理此响应可以重定向到登录页面(或者可能是同一页面,因为 Shiro 将重定向到登录但可以配置为记住您尝试去的地方,因此采取成功登录后用户返回正确的页面)。

我的过滤器实现返回 Http 代码 401 以及“WWW-Authentication”标头和自定义“挑战方案”(如果您进行了基本身份验证挑战,那么浏览器将弹出其基本身份验证对话框 - 已经有一个 Shiro 过滤器这样做)。

在您的 Ajax 调用中,您需要检测此响应,目前我有一个笨拙的错误回调可以做到这一点,但我认为应该可以修改 JavaScript 库(JQuery 等)以无缝处理。

【讨论】:

那部分确实有效,我将 ajax 组件重定向到登录页面。与此相关的最后一个问题是页面刷新。我可以使用 onunload 来捕捉页面刷新,但如果它发生在会话超时之后,页面就消失了。每当发生某些事件(如 DOM 刷新)时,我都会在页面中放置警报以弹出,但在会话超时后刷新页面时不会弹出任何内容。有没有办法抓住这个?这是我尝试过的一些代码 sn-ps: 试图格式化代码,但我忘了如何:jQuery(document).ready(function() var request = jQuery.ajax( url: "viewJobActivity.faces", type: "POST" ); request.done(function(msg) alert('done'); ); request.fail(function(jqXHR, textStatus) alert("请求失败:" + textStatus ); ); ); 我尝试的另一种方式:jQuery.ajax( // Define AJAX properties. method: "get", url: "viewJobActivity.faces", // Define the succss method. success: function() alert( "Success!" ); , // Define the error method. error: function( objAJAXRequest, strError ) alert("Error! Type: " + strError); ); 对于那些使用 Apache Shiro 和 Primefaces 来处理会话超时的人:jquery 插件,称为 sessionTimeout。这个插件的作用是等到预设的时间,然后显示一个对话框,警告用户他们的会话即将超时。然后他们可以继续注销或留在页面上,这会重置计时器。如果用户不做任何事情,那么页面最终会重定向(时间由您设置)到登录页面。我的注销页面只调用托管 bean 调用 Shiro 注销方法,然后返回“window.location.replace('login.faces')”。

以上是关于JSF 2 + Spring 3 + Shiro - 会话超时不重定向到登录页面的主要内容,如果未能解决你的问题,请参考以下文章

可以使用 Shiro 设置 JSF 页面级别权限吗

Shiro-继承Spring

JSF 2.3 与 Spring 4.3 @Inject @ManagedProperty 问题

将 PrimeFaces 与 JSF 一起使用时 Shiro 重定向到错误的位置

何时从容器管理的安全性转移到 Apache Shiro、Spring Security 等替代方案?

何时从容器管理的安全性转移到 Apache Shiro、Spring Security 等替代方案?