php微服务session,微服务session落坑记

0c8a4f09deeb88115138d10fa60e139c.png

本文适用于对session、cookie有一定了解的同学,主要以问题定位过程为线索,简单讲述tomcat session生成机制、oauth2认证过程以及spring方法参数映射处理等内容

背景知识:

session:由于http协议无状态,为了保存用户状态信息,web容器支持session管理机制,当客户端请求web应用时,如果在处理过程中调用了request.getSession()方法,则web容器会先根据url或者cookie中上传的JSESSIONID(默认,可以另行设置,该值会被设置到request对象的requestedSessionId字段)查找对应session,如果获取不到将自动创建一个session对象;当session过期或被放弃后,服务器将终止该session

protected Session doGetSession(boolean create) {

// 略去部分代码

if (requestedSessionId != null) {

session = manager.findSession(requestedSessionId);

// 略去部分代码

String sessionId = getRequestedSessionId();

// 略去部分代码

session = manager.createSession(sessionId);

// 创建cookie并写入response

if (session != null

&& context.getServletContext()

.getEffectiveSessionTrackingModes()

.contains(SessionTrackingMode.COOKIE)) {

Cookie cookie =

ApplicationSessionCookieConfig.createSessionCookie(

context, session.getIdInternal(), isSecure());

response.addSessionCookieInternal(cookie);

}

// 略去部分代码

}

复制代码

cookie:为了服务器能够识别不同的客户端,客户端通过cookie保存服务端返回的数据(如JSESSIONID,tomcat服务器默认的session对应的cookie key为JSESSIONID),然后服务端通过客户端请求时放在http header中的cookie数据找到之前为客户端创建的session;cookie分为会话cookie和持久cookie,会话Cookie浏览器会话有效期间存在,持久cookie服务端会设置http header 缓存相关字段指示客户端缓存策略,cookie传到客户端后,保存在某个目录下

oauth2:oauth是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用,可以用于微服务环境下的公共鉴权,而本文服务鉴权走的就是oauth2

前人挖坑后人落,都是框架惹的祸

问题特征:

需求上线在即,发现某个接口请求后会新生成JSESSIONID并以Cookie形式回写浏览器,导致后续请求鉴权失败,必现

服务相互调用关系比较复杂,需要在开发环境测试该功能,本地没有测试

问题定位过程:

交流得知,此前定位过程中,将被请求方法体代码全部注销后,问题仍然存在,于是错过了查看问题代码(其实是方法参数出了问题),尽早定位出问题的好机会

怀疑是否nginx会话保持策略导致的问题(但是该策略应该会对所有请求均产生影响,而不只是单个请求),查看nginx.conf配置,该服务没有走负载均衡

怀疑是否nginx对该请求路径(路径中包含auth敏感字段)做了特殊配置,但查看配置,nginx对于该服务请求路径配置规则很简单,且将请求路径中auth字段删掉后测试,问题仍然存在

怀疑是否有外围代码重写了cookie,搜索没找到相关代码

梳理服务鉴权过程(见top图,图中做了缩略,将公共认证服务删除,直接对接oauth2),描述如下:

1)认证鉴权逻辑被封装在了公共Filter中,对所有请求进行拦截,判断是否已登录

2)如果没有上传JSESSIONID或者无法据其在redis找到session及token信息,返回客户端重定向到login接口

3)客户端调用login接口:服务端调用oauth2(其实有个公共的鉴权服务)认证合法性,将认证返回的token信息融合自身的JSESSIONID写入redis,随后将服务端JSESSIONID写回客户端cookie,坑:此处复用了tomcat默认的JSESSIONID,推测是为了复用request的getRequestedSessionId方法,该方法会直接取客户端cookie提交的JSESSIONID,业务中多次用到了getRequestedSessionId方法,tomcat session和服务认证返回session除了都叫JSESSIONID外,没有半毛钱关系,但是因为重名,相互之间会覆写

4)客户端带着认证返回的JSESSIONID继续调用之前的业务接口,通过认证,走业务逻辑,其实此时tomcat中的JSESSIONID和上传的JSESSIONID不一致,根据上传的JSESSIONID在tomcat是找不到对应session的

5)认证过程还有其他逻辑,此处做了删减,不影响主体流程

梳理之后,发现二者之间虽然key一致但是值不同,而且彼此会干扰,于是怀疑外围代码调用了getSession方法,搜索代码未找到

查看请求路径对应方法,方法中使用了session参数,但是方法体中未使用该参数,联想到spring的参数值自动映射机制(见ServletRequestMethodArgumentResolver),在为session赋值的过程中调用了getSession方法,进而由于在tomcat找不到对应session而新建、回写相关cookie到客户端

public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

Class> paramType = parameter.getParameterType();

// 略去部分代码

if (HttpSession.class.isAssignableFrom(paramType)) {

HttpSession session = request.getSession();

// 略去部分代码

}

}

复制代码

删除参数,测试,问题解决

坑:

使用该认证机制的服务的业务方法中不要使用tomcat的session机制(如getSession或session参数),否则就会出现这个问题

解决方案:

针对此问题,将session参数去掉

将认证机制的JSESSIONID换成另外一个名字,但是改动量比较大,可能会有其他坑

走分布式session(token)解决方案,将tomcat的session管理机制和分布式session(token)结合起来

采用jwt token形式鉴权,服务端不保存token,仅做验证和刷新

欢迎关注我的微信公众号

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值