场景:
在后台管理系统中,当用户登录了之后,会将用户信息放到session中,并将set-cookie=jsessionId的信息通过response header写回到浏览器中。
之后每次已登录用户发出请求的时候,浏览器会拿着cookie中的jsessionId,到一个Filter中做用户已登录校验。
那么有没有好奇,上面这个过程是如何发生的呢?
注意:tomcat(org.apache.catalina)下有Request和Session对象,在调用 HttpServletRequest 的 getSession 方法时,由 Web 容器(比如 Tomcat)创建的
问题:现在的web容器都支持将session存储在第三方中间件(如redis)中,为什么很多公司喜欢绕过容器,直接在应用中将会话数据存入中间件中?比如spring session
回答:用Web容器的Session方案需要侵入特定的Web容器,用Spring Session可能比较简单,不需要跟特定的Servlet容器打交道。
这正是Spring喜欢做的事情,它使得程序员甚至感觉不到Servlet容器的存在,可以专心开发Web应用。但是Spring到底做了什么,Spring Session是如何实现的,我们还是有必要了解了解
其实它是通过Servlet规范中的Filter机制(SessionRepositoryFilter)拦截了所有Servlet请求,偷梁换柱,将标准的Servlet请求对象包装了一下(SessionRepositoryRequestWrapper),换成它自己的Request包装类对象,这样当程序员通过包装后的Request对象的getSession方法拿Session时(重写 HttpServletRequest 的 getSession 方法),是通过Spring拿Session,没Web容器什么事了。返回的时候使用包装Response对象(SessionRepositoryResponseWrapper),reponse 写入 sessionId。
源码解析:
login流程
在login的时候,通过
session.setAttribute("user", user);
将其set到attributes中
if (requestedSessionId != null) {
try {
session = manager.findSession(requestedSessionId);
通过下面这个方法,将session cookie放到response中
response.addSessionCookieInternal(cookie);
这个cookie对象
其会将cookie放到response中,当login完成后,会将cookie(jsessionId)更新到浏览器中。
当用户请求url的时候
springmvc会将浏览器的请求转换为Request对象,其中cookie中的jsessionId会转换为request中的字段
springmvc会将http请求 转换为HttpServletRequest对象,在这个过程中,会把http request headers中的cookie转换为HttpServletRequest对象中的requestedSessionId字段
用户点击退出
将服务器session设置为超时 浏览器cookie并没有做清除处理
三种情况下的流程图
其中的SessionFilter是我们自定义的做用户是否登录的过滤器
在spring security中的使用
也是访问AuthenticatorBase,之后生成session,并将cookie写到response中
同样也是在login的时候