如何阻止特定网址的shiro会话超时?

时间:2015-10-22 12:36:30

标签: spring-mvc session shiro

我已经在我的webapp中使用Spring配置了Shiro全局超时,因此如果我的网页(客户端)在过去30分钟内没有任何请求(只是实例),则客户端的会话将超时并且页面重定向到登录页面。这已经可以了。我的问题如下:

网页在后台有一个ajax请求,它将按设定的时间间隔请求服务器。每次请求都会清除Shiro中会话的超时计数器,因此客户端会话永远不会超时!

是否可以配置Shiro使某些特定网址无法清除或刷新会话超时???

很难对问题进行标题,也非常难以进行搜索。但我觉得总有一些人有同样的要求!任何人都有任何想法,请告诉我。非常感谢〜

我的部分配置如下,

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="filters">
        <map>
            <entry key="ssl" value-ref="sslFilter"/>
            <entry key="login" value-ref="userLoginFilter"/>
            <entry key="nosessi" value-ref="unSessionFilter"/>
        </map>
    </property>
    <property name="securityManager" ref="securityManager"/>
    <property name="filterChainDefinitions">
        <value>
            /alarms/current-alarm-states = nosessi
            /js/** = anon
            /css/** = anon
            /images/** = anon
            /login = anon,ssl
            /login/** = anon,ssl
            /** = login,ssl
        </value>
    </property>
</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realms">
        <list>
            <ref bean="userRealm"/>
        </list>
    </property>
    <property name="sessionManager" ref="sessionManager"/>
</bean>

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="sessionListeners">
        <list>
            <ref bean="sessionListener"/>
            <ref bean="tsSessionListener"/>
        </list>
    </property>
    <!-- 3 minutes: 180000 -->
    <property name="globalSessionTimeout" value="180000"/>
    <property name="sessionIdCookie.name" value="MY_SESSIONID"/>
</bean>

2 个答案:

答案 0 :(得分:2)

您无法在Shiro中进行配置。超时与shiro无关,它是一个servlet容器配置。

用户会话是服务器中的一个单个对象,只要您的请求发送会话cookie(大部分时间都是JSESSIONID),并且servlet容器可以找到会话对象(因此它还没有超时) ,超时将被重置。

您必须自己创建一些过滤器以跟踪超时。对于每个请求,您可以使用会话侦听器(http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSessionListener.html)创建会话计时器。例如,您可以使用Timer对象。每次请求进入时,过滤器都会获取会话计时器并重置它,除非那些网址你不希望这种情况发生。

您还可以查看Vaadin的源代码,因为它们具有类似的设置并以某种方式处理它:https://vaadin.com/book/-/page/application.lifecycle.html#application.lifecycle.ui-expiration

答案 1 :(得分:1)

我调试了shiro,跟踪会话的行为。我发现上次访问的时间是在ShiroFilterFactoryBean类中更新的,之后,大多数过滤器将使用会话的lastAccessTime检查请求时间,除了anon过滤器。

基于此,我想出了一个解决方案。扩展ShiroFilterFactoryBean并覆盖更新会话访问时间的方法,该方法不会为特殊URL更新。此外,特殊必须使用anon过滤器。

public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean {

@Override
protected AbstractShiroFilter createInstance() throws Exception {
    SecurityManager securityManager = this.getSecurityManager();
    String manager1;
    if(securityManager == null) {
        manager1 = "SecurityManager property must be set.";
        throw new BeanInitializationException(manager1);
    } else if(!(securityManager instanceof WebSecurityManager)) {
        manager1 = "The security manager does not implement the WebSecurityManager interface.";
        throw new BeanInitializationException(manager1);
    } else {
        FilterChainManager manager = this.createFilterChainManager();
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        return new NmsShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
    }
}

@Override
public Class getObjectType() {
    return NmsShiroFilterFactoryBean.SpringShiroFilter.class;
}

private static final class SpringShiroFilter extends AbstractShiroFilter {
    protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
        if(webSecurityManager == null) {
            throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
        } else {
            this.setSecurityManager(webSecurityManager);
            if(resolver != null) {
                this.setFilterChainResolver(resolver);
            }

        }
    }

    @Override
    protected void updateSessionLastAccessTime(ServletRequest request, ServletResponse response) {
        if(request instanceof HttpServletRequest) {
            String requestURI = ((HttpServletRequest) request).getRequestURI();
            if(requestURI.equals("/alarms/current-alarm-states")) { // no update the last access time of session
                return;
            }
        }
        super.updateSessionLastAccessTime(request, response);
    }
}

}