【问题标题】:How to block shiro's session timeout for a specific url?如何阻止特定 url 的 shiro 会话超时?
【发布时间】:2016-01-21 17:50:04
【问题描述】:

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

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

是否可以配置Shiro使某些特定的url不清除或刷新会话超时???

很难为问题命名,搜索也是如此。但我想总有一些人有同样的要求!任何人有任何想法,请告诉我。非常感谢~

我的部分配置如下,

<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>

【问题讨论】:

    标签: spring-mvc session shiro


    【解决方案1】:

    你不能在 Shiro 中配置它。超时与shiro无关,是servlet容器配置。

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

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

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

    【讨论】:

    • Shiro 有 Native Sessions,比如 DefaultWebSessionManager 类。 可跨 servlet 容器移植(例如测试中的 Jetty,生产中的 Tomcat 或 JBoss),或者您想要控制特定的会话/集群功能,您可以启用 Shiro 的本机会话管理。 --- 来自 shiro 参考.那么,我们可以做点什么吗?
    • 你说的也是一种好方法。我去试试,谢谢~_~
    【解决方案2】:

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

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

    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);
        }
    }
    

    }

    【讨论】:

    • 这对我不起作用 .. sessionLastAccessTime 仍然使用 anon ant authc 更新(仅使用本机会话,而不是 shiro 会话).. 虽然 updateSeesionLastAccesTime 被触及:(
    猜你喜欢
    • 2012-09-27
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 2014-08-18
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    相关资源
    最近更新 更多