Shiro登出后跳转登录页失败,报UnknownSessionException求助
我之前也碰到过一模一样的坑!咱们先把问题拆解清楚,再一步步解决:
问题根源分析
从你贴的异常堆栈能明确看到:
org.apache.shiro.session.UnknownSessionException: There is no session with id [e6af7582-badd-4c0d-a296-12ebee91f8e5]
问题出在Spring的SessionFlashMapManager——当你调用SecurityUtils.getSubject().logout()后,Shiro已经彻底销毁了当前会话,但Spring在处理redirect:/login跳转时,会自动尝试从Session中读取FlashMap数据(用来传递跨请求的临时参数),这时候访问已销毁的Session就触发了异常。
可行解决方案
方案1:用原生Servlet跳转绕过FlashMap处理(最直接)
放弃Spring的ModelAndView跳转,改用Servlet原生的sendRedirect,同时手动清空Session,彻底避免Spring触发FlashMap的检索逻辑:
// 执行Shiro登出 SecurityUtils.getSubject().logout(); // 手动销毁当前请求绑定的Session request.getSession().invalidate(); // 原生跳转至登录页 response.sendRedirect("/login"); // 返回null,告诉Spring不需要再处理视图 return null;
方案2:自定义FlashMapManager捕获异常
如果你必须保留ModelAndView的跳转方式,可以自定义一个安全的FlashMapManager,重写retrieveFlashMaps方法,捕获会话不存在的异常:
import org.apache.shiro.session.UnknownSessionException; import org.springframework.web.servlet.support.SessionFlashMapManager; import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.List; public class SafeSessionFlashMapManager extends SessionFlashMapManager { @Override protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request) { try { // 正常情况调用父类方法 return super.retrieveFlashMaps(request); } catch (UnknownSessionException e) { // 会话已销毁时,返回空列表即可 return Collections.emptyList(); } } }
然后在Spring的XML配置中替换默认的FlashMapManager:
<!-- 自定义安全FlashMapManager --> <bean id="safeFlashMapManager" class="com.yourpackage.SafeSessionFlashMapManager"/> <!-- 配置RequestMappingHandlerAdapter使用自定义的FlashMapManager --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="flashMapManager" ref="safeFlashMapManager"/> </bean>
方案3:检查URL重写过滤器的执行顺序
从堆栈能看到你的UrlRewritFilter在Shiro过滤器之后执行了forward操作,如果这个过滤器里有访问Session的逻辑,也可能触发异常。可以调整web.xml中过滤器的顺序,让Shiro过滤器在UrlRewritFilter之后执行,确保重写逻辑在会话销毁前完成。
总结
最快速的解决方式是方案1,直接用原生跳转绕过Spring的FlashMap机制;如果项目依赖FlashMap传递参数,方案2是更合适的长期解决方案。
内容的提问来源于stack exchange,提问作者Girish

