【问题标题】:How to catch redis.serializer.SerializationException如何捕获 redis.serializer.SerializationException
【发布时间】:2017-10-06 08:45:38
【问题描述】:

我在 Spring 框架(4.1.6)上有应用程序,使用 Spring Security 4.0.1。我在应用程序中使用@EnableRedisHttpSession 和@EnableSpringHttpSession,一切正常。但是在将 Spring Security 版本升级到 4.2.1 后,我在新包上的序列化旧版本出现问题。

我的堆栈跟踪是:

org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [dispatcher] in context with path [] threw exception
 org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.InvalidClassException: org.springframework.security.core.context.SecurityContextImpl; local class incompatible: stream classdesc serialVersionUID = 400, local class serialVersionUID = 420
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:41)
    at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:316)
    at org.springframework.data.redis.core.AbstractOperations.deserializeHashMap(AbstractOperations.java:277)
    at org.springframework.data.redis.core.DefaultHashOperations.entries(DefaultHashOperations.java:227)
    at org.springframework.data.redis.core.DefaultBoundHashOperations.entries(DefaultBoundHashOperations.java:101)
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:421)
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:392)
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:252)
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:270)
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:286)
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:170)
    at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
    at org.springframework.security.web.context.HttpSessionSecurityContextRepository.loadContext(HttpSessionSecurityContextRepository.java:110)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:100)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:126)
    at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:65)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1441)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.InvalidClassException: org.springframework.security.core.context.SecurityContextImpl; local class incompatible: stream classdesc serialVersionUID = 400, local class serialVersionUID = 420
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78)
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36)
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:39)
    ... 53 more

我不明白,如何在 Spring 中捕获此异常。

我的问题是:“如何捕捉这个异常,进一步显示一个简单的错误页面?”。

附:我无法清理旧会话。任何帮助都会很酷!

【问题讨论】:

    标签: java spring spring-mvc spring-security redis


    【解决方案1】:

    您可以使用 Spring AOP、@Aspect 处理异常

        public class ErrorInterceptor{
        @AfterThrowing(pointcut = "execution(* your.package..* (..))", throwing = "ex")
        public void errorInterceptorForSerializationException(SerializationException ex) {
            // DO SOMETHING HERE WITH EX
            logger.error( ex.getCause().getMessage());
        }
     @AfterThrowing(pointcut = "execution(* your.package..* (..))", throwing = "ex")
        public void errorInterceptorForSerializationFailedException(SerializationFailedException ex) {
            // DO SOMETHING HERE WITH EX
            logger.error( ex.getCause().getMessage());
        }
        }
    

    【讨论】:

      【解决方案2】:

      从 Spring Boot 2.3.3、Spring 5.x 开始,Spring Session 仍然不支持。

      也就是说,只要所有应用程序都具有相当最新的 Spring Security 版本,该项目就会停止更新 serialVersionUID 的值以最大程度地减少版本冲突。

      否则,有一些变通方法可以简化转换,或者,如果您愿意做一些工作,可以将 SecurityContext 类序列化为 JSON。

      但可用的信息是分散的,有时是相互矛盾的。小心行事。

      要点:

      更多细节:

      1. Spring Session 上记录了许多与此问题相关的问题。没有人真正完全解决问题。

      2. 最简单的解决方法是删除最有可能迫使用户再次登录的“旧”会话(但是,如果使用记住我的令牌,用户可能看不到)。

      3. 通过一些更深入的 Spring Boot 配置黑客攻击,可能可以将 Spring Security 会话存储为 JSON 格式。这可能允许运行不同版本的 Spring Security 的不同应用共享会话。 YMMV。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-19
        • 2012-03-27
        • 2021-12-11
        • 2014-12-10
        • 1970-01-01
        • 2021-06-15
        • 2017-08-19
        • 1970-01-01
        相关资源
        最近更新 更多