Reputation: 83
I have configured the Shiro global timeout with Spring in my webapp, so if my web page(client) doesn't have any request during the past 30 minutes(just instance), the session of the client will timeout and page redirect to a login page. This is already ok. My problem is as following:
The web page has a ajax request in the background, which will request the server at set intervals. And every time it requests will clear the timeout counter of the session in Shiro, so the client session will never timeout!
Is it possible to configure the Shiro to make some specific urls will not clear or refresh the session timeout???
It's really hard to title the problem, also for searching. But I think there always are some people have the same requirement! Anyone has any idea, please tell me. Thank you very much~
My part configuration is as follows,
<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>
Upvotes: 1
Views: 1222
Reputation: 83
I debug the shiro, track the behavior of session. And I found that the last accessed time was updated in class ShiroFilterFactoryBean, after that, Most Filters will check the request time with lastAccessTime of session except anon filter.
Based on this, I figured out a solution. Extend the ShiroFilterFactoryBean and override the method of updating session access time which will not update for the special url. Besides, the special has to use anon filter.
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);
}
}
}
Upvotes: 1
Reputation: 4016
You can't configure this in Shiro. The timeout has nothing to do with shiro, it is a servlet container configuration.
The user session is one single object in the server and as long as your requests send the session cookie (JSESSIONID most of the time) and the servlet container can find the session object (and thus it hasn't timed out yet), the timeout will be reset.
You will have to create some Filter yourself to keep track of a timeout. For each request you can create a session timer using a session listener (http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSessionListener.html). You could use a Timer object for this for example. Each time a request comes in, the filter gets the session timer and resets it, except on those url's you do not want that to happen.
You could also look in the source code of Vaadin, as they have a similar setup and have somehow dealt with it: https://vaadin.com/book/-/page/application.lifecycle.html#application.lifecycle.ui-expiration
Upvotes: 2