专栏首页Linyb极客之路springcloud用redis做session共享出现类反序列化失败问题

springcloud用redis做session共享出现类反序列化失败问题

前言

前段时间项目组打算把公司的一个老项目当做现有系统的子模块,现有系统的技术框架主要是采用springcloud,用redis来做session共享。老项目的用户鉴权采用jwt,鉴权成功后,会把对象存到session里面,当时为了尽量少动老项目的代码,老项目单独维护自己的用户对象,其他模块的用户对象则由用户服务模块统一提供。当时改造完后,访问老模块时候,报了如下的错误:

{"timestamp":1548981972259,"status":500,"error":"Internal Server Error","exception":"org.springframework.data.redis.serializer.SerializationException","message":"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 org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException: xxx.model.UserInfoDTO","path":"/xxx/xx"}
0

当时这个错误还不是从控制台或者日志查出来的,而是通过fiddler抓包抓出来的。从错误的信息异常来看,是因为类找不到而导致redis反序列对象失败。问题点找出来了,接下来就是要解决,当时解决的问题的方法,有如下几种

1、老项目的用户对象也统一由用户服务模块提供

这种方案是可以解决用户对象反序列化失败问题,因为所有服务模块的用户对象都是来自用户服务模块,但因为老项目又有其他实体对象也用session来存放,所以上面方案只能解决用户对象问题,没法解决其他实体对象问题

2、老项目的实体对象都转换成json,存放到session,要用对象的话,再把json转成对象

这种方法是可以很完美的解决对象反序列化问题,但因为老项目有太多的实体对象都存放在session中,而项目组的成员对老项目的业务不了解,很容易改漏掉

3、老项目不进行session共享,单独维护自己的session

项目组后面采用的是这种方案,理由是

  • 老项目是采用jwt来进行鉴权,其实是可以脱离session
  • 老项目项目配置自己的contextPath,而不是采用默认的contextpath /
  • 根据开闭原则,对扩展开放,对修改关闭,如果要改造,可以做如下两件事情
  1. 在网关鉴权方面,多加一层jwt鉴权过滤
  2. 配置老项目的自己cookie

鉴权其核心代码如下

@Component
public class JwtFilter extends ZuulFilter {

    private Logger logger = LoggerFactory.getLogger(JwtFilter.class);

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        logger.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());
        String requestUri = request.getRequestURI();
        if(requestUri.startsWith("/Oxford")){
            return true;
        }
        return false;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        HttpServletResponse response = ctx.getResponse();
        Cookie[] cookies = request.getCookies();
        Cookie jwtTokenCokie = null;
        if(cookies != null){
            for(Cookie cookie : cookies){
                if(cookie.getName().equalsIgnoreCase(JwtConstant.JWT_COOKIE_NAME)){
                    jwtTokenCokie = cookie;
                    break;
                }
            }
        }

        if(jwtTokenCokie != null && jwtTokenCokie.getValue() != null && jwtTokenCokie.getValue().startsWith(JwtConstant
                .JWT_COOKIE_VALUE_PRE)){
            HttpSession httpSession = request.getSession(false);
            if(httpSession != null){
                // 已经登录,则根据时间,适当延长
                Claims claims = JwtTokenUtil.getClaimsWithoutCheckTime(jwtTokenCokie.getValue().substring(JwtConstant
                        .JWT_COOKIE_VALUE_PRE.length()));
                if (claims.getExpiration().before(DateUtils.addMinutes(new Date(), 15))) {
                    claims.setExpiration(DateUtils.addMinutes(new Date(), 30));
                    jwtTokenCokie.setValue(JwtConstant.JWT_COOKIE_VALUE_PRE+JwtTokenUtil.generateToken(claims));
                    jwtTokenCokie.setPath("/Oxford");
                    jwtTokenCokie.setHttpOnly(true);
                    response.addCookie(jwtTokenCokie);
                }
            }else{
       //          没有登录的话,要将token时间改成超时
                String expirationToken = JwtTokenUtil.refreshTokenWithoutCheckTime(jwtTokenCokie.getValue().substring(JwtConstant
                        .JWT_COOKIE_VALUE_PRE.length()), DateUtils.addDays(new Date(),
                        -2));
                jwtTokenCokie.setValue(JwtConstant.JWT_COOKIE_VALUE_PRE+expirationToken);
                jwtTokenCokie.setPath("/Oxford");
                response.addCookie(jwtTokenCokie);
            }
        }
        return null;
    }
}

cookie配置其核心代码如下

@Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
        defaultCookieSerializer.setCookieName("oxfordSessionId");
        defaultCookieSerializer.setCookiePath("/Oxford");
        return defaultCookieSerializer;
    }

注:cookiePath要和contextPath配置一致,domainName没配置,默认同域

总结

1、用fiddler来抓包挺好用的

2、当问题的解决方案很多时,要优先考虑项目所处的现状,比如是否适合大改动,研发的技术储备能力是否足够等

本文分享自微信公众号 - Linyb极客之路(gh_c420b2cf6b47)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 聊聊flink的Table Formats

    flink-table_2.11-1.7.1-sources.jar!/org/apache/flink/table/descriptors/ConnectTa...

    codecraft
  • hive字符串函数

    hive字符串函数 1. 字符串长度函数:length 语法: length(string A) 返回值: int 说明:返回字符串A的长度 举例:hive> ...

    学到老
  • R语言中文分词工具

    使用默认方法安装相关R中文文本挖掘包(tmcn、Rwordseg、Rweibo)时,会出现安装失败。合适的方法是:通过源代码安装相关包的程序:手工下载源代码及其...

    学到老
  • 聊聊flink的Execution Plan Visualization

    本文主要研究一下flink的Execution Plan Visualization

    codecraft
  • JcJc人工智能错别字校对系统API(网站错别字检查)

    中文校对软件 http://cuobiezi.net/zigen_jiaodui.html

    田春峰-JCJC错别字检测
  • Python文件处理

    很多初学者都没有在程序中写异常的意识,这会给程序带来很多危险,比如程序突然崩溃,攻击者可能会根据traceback对代码发起攻击,一般在涉及到数据交互,输入输出...

    刘开心_1266679
  • Python爬虫入门教程 6-100 蜂鸟网图片爬取之一

    国庆假日结束了,新的工作又开始了,今天我们继续爬取一个网站,这个网站为 http://image.fengniao.com/ ,蜂鸟一个摄影大牛聚集的地方,本教...

    梦想橡皮擦
  • python 序列化数据:pickle与json ,dumps与loads,解决can't pickle _thread.lock objects

    pickle 只能在python中用python文件间序列化,实现了两个python 内存数据的交互(可序列化任何对象(类,列表)) json 在任何软件间可...

    学到老
  • Java 错别字检查接口 API

    为了方便广大程序员朋友快速把错别字检查功能集成到自己的系统中,我们开发了一个支持HTTP协议的 Java 错别字检查接口 API,代码放在了 github 上...

    田春峰-JCJC错别字检测
  • 关于R安装中文分词包安装不上的问题install.packages(\"tm\")

    学到老

扫码关注云+社区

领取腾讯云代金券