我已经在我的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>
答案 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);
}
}
}