如何将自定义Rest Shiro过滤器迁移至shiro.ini并配置API会话超时
技术问题与配置需求
初始问题
- 能否将旧的Rest过滤器移植至shiro.ini中配置?
- 在shiro.ini中初始化过滤器后,能否通过Java代码扩展其doFilter()方法?
注:当前遇到错误处理异常,疑似Shiro Bug,无需协助编写代码,仅需方向指引。
现有代码与配置
MyRestFilter的doFilter()实现
@Override @SneakyThrows(Throwable.class) public void doFilter(final HttpServletRequest request, final HttpServletResponse response, HttpSession httpSession, final FilterChain chain) throws ServletException, IOException { debugRequest(request); List<String> sessionIds = Servlets.getRequestQueryStringMap(request).get(SESSION_ID); String sessionId = sessionIds == null? null : Iterables.getOnlyElement(sessionIds); String sessionIdHeader = request.getHeader(SESSION_ID_HEADER); if(sessionId == null) { sessionId = sessionIdHeader; } ThreadContext.unbindSubject(); ThreadContext.bind(securityManager); if(sessionId != null) { // strip out host / instance ID from the session sessionId = sessionId.replaceFirst("\\.[\\w_\\-+]+$", ""); Subject subject = new Subject.Builder().sessionId(sessionId).buildSubject(); Session session = subject.getSession(false); if(session != null) { session.touch(); // this should not be necessary, but due to Shiro bug, it is StatefulUtil.pingStateful(session); } if(subject.getPrincipal() == null) { response.sendError(HttpStatus.SC_UNAUTHORIZED, "Unauthorized API Call"); } else { try { subject.execute(() -> { SharedWebstats webStats = Beans.getReference(SharedWebstats.class); webStats.webStats("mobile"); if (chain != null) { chain.doFilter(request, response); } return null; }); } catch(ExecutionException e) { // unwrap Shiro's ExecutionException, interferes // with global exceptino handling mechanisms Throwable cause = e.getCause(); if (cause != null) { throw cause; } else { throw e; } } } } else { chain.doFilter(request, response); } ThreadContext.unbindSecurityManager(); }
MyRestFilter的init()实现(存在会话超时配置问题)
@Override public void init() throws ServletException { //securityManager = new WebIniSecurityManagerFactory("classpath:META-INF/shiro.ini").createInstance(); securityManager = WebIniSecurityManagerFactory("classpath:META-INF/shiro.ini").createInstance(); int sessionTimeout = WebXml.INSTANCE.getSessionTimeout(); DefaultSecurityManager dsm = (DefaultSecurityManager)securityManager; DefaultSessionManager sm = (DefaultSessionManager)dsm.getSessionManager(); sm.setGlobalSessionTimeout(sessionTimeout * 60 * 1000); realmCache.putAll(securityManager); ssse.addSessionListeners(sm.getSessionListeners()); } private org.apache.shiro.mgt.SecurityManager securityManager; private @Inject RealmCacheHolder realmCache; private @Inject ShiroSessionScopeExtension ssse;
当前Web.xml配置
<filter> <filter-name>ShiroFilter</filter-name> <filter-class>com.dependencyfromhell.shiro.ee.filters.ShiroFilter</filter-class> <async-supported>true</async-supported> </filter> <context-param> <param-name>shiroConfigLocations</param-name> <param-value>classpath:META-INF/shiro.ini</param-value> </context-param> <!-- Security - Enforce Filter Ordering --> <filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> <filter-mapping> <filter-name>MyRestFilter</filter-name> <url-pattern/> </filter-mapping>
期望的shiro.ini配置
# rest support rest = MyRestFilter #Rest api /api/* = MyRestFilter
核心疑问
能否在shiro.ini中配置MyRestFilter的会话超时,同时保留Java类中的doFilter()逻辑?
方向指引
1. 过滤器移植至shiro.ini的可行性
完全可行。Shiro支持在ini文件中配置自定义过滤器:
- 确保
MyRestFilter继承自Shiro的AccessControlFilter/PathMatchingFilter,或实现javax.servlet.Filter并适配Shiro过滤器规范。 - 按你期望的ini格式配置即可,还能通过
rest.paramName=paramValue的方式给过滤器注入配置参数。
2. 保留doFilter()逻辑并扩展
可以完全保留原有逻辑:
- 配置到shiro.ini后,Java类的doFilter()逻辑会正常执行,无需修改。
- 若要扩展,直接修改Java类的doFilter()方法即可,ini配置仅负责实例化过滤器和绑定路径,不影响代码逻辑。
3. 会话超时的配置方案(针对/api/路径)
Shiro全局会话超时无法按路径区分,推荐以下两种方案:
- 方案一:在过滤器中动态设置
删除init()中设置全局会话超时的代码,在doFilter()中判断请求路径,匹配/api/*时单独设置会话超时:
其中if(session != null && request.getRequestURI().startsWith("/api/")){ session.setTimeout(customApiTimeout * 60 * 1000); }customApiTimeout可通过ini注入:给MyRestFilter添加setter方法,在ini中配置rest.customApiTimeout=30。 - 方案二:多SessionManager配置
为Rest路径单独配置SessionManager,通过Shiro路径规则绑定,但实现复杂度较高,优先推荐方案一。
4. 错误处理异常排查方向
- 检查Shiro版本是否存在已知的ExecutionException相关Bug,尝试升级到最新稳定版。
- 确认全局异常处理器能否正确捕获过滤器抛出的异常,重点排查异常抛出后是否被其他拦截器拦截或丢失。
内容的提问来源于stack exchange,提问作者nettie
相关产品推荐
相关产品推荐

