5.会话管理

SessionManager用于管理Shiro中的Session信息。Session也就是我们通常说的会话,会话是用户在使用应用程序一段时间内携带的数据。传统的会话一般是基于Web容器(如:Tomcat、EJB环境等)。Shiro提供的Session可以在任何环境中使用,不再依赖于其他容器。

Session有一些实现类,包括SimpleSession、HttpServletSession和DelegatingSession等。SimpleSession是Shiro提供的一种简单实现,HttpServletSession是基于Sevlet中Session来实现的,DelegatingSession是一种委托机制,委托给SessionManager来实现。

下面是有关会话和过滤器的类关系图:

 

SessionManager分析

SessionManager管理着Session的创建、操作以及清除等。SessionManager有一些子接口,包括NativeSessionManager、ValidatingSessionManager和WebSessionManager。每个接口都提供了相关的抽象类AbstractSessionManager、AbstractNativeSessionManager、AbstractValidatingSessionManager。

SessionManager主要负责创建Session和获取Session,NativeSessionManager接口中包含了所有对Session的操作,这些操作方法和Session接口中是一致的,而ValidatingSessionManager接口提供了对Session校验的支持。

AbstractNativeSessionManager分析

该类负责管理Session的操作,但操作的具体实现是由Session自己实现的。相当于对Session操作前后做代理。

AbstractValidatingSessionManager分析

AbstractValidatingSessionManager的作用是定期的校验所有有效的Session状态,因为Session可能被停止或过期。该类继承了上面分析的AbstractNativeSessionManager,然后实现了ValidatingSessionManager接口中的validateSessions()方法。此类负责校验Session。另外此类还实现了Destroyable接口,表示销毁时应该处理销毁功能。该类会启动调度作业来校验Session,而调度作业的真正内容是检测每个Session的validate()方法。

5.1会话创建流程

具体流程如下:

1.发起请求时,首先会来到代理类DelegatingFilterProxy.doFilter方法中

先判断filter有没有初始化,没有初始化就现在初始化。然后调用正在的doFilter方法。也就是OncePerRequestFilter.doFilter

2.因为ShiroFilterFactoryBean 实现了FactoryBean,在springbean 进行依赖注入时getBean,此时会调用ShiroFilterFactoryBean.getObject的方法。

 

返回真正的过滤类为:SpringShiroFilter

3.SpringShiroFilter实现了OncePerRequestFilter,那么调用OncePerRequestFilter.doFilter也就是再执行我们的shiro过滤器了。

 4.进入AbstractShiroFilter.doFilterInternal,重点createSubject。

 5.跟下去进入:DefaultSecurityManager.createSubject

 6.进入resolveSession(context)方法

 7.进入resolveContextSession(context)方法

 8.继续跟进

以上就完成了Session的获取。

9.接着走context = resolvePrincipals(context),获取你有没有登录的Principal信息。显然null。登录认证AuthenticationInfo也null,session也null。

 10.开始进行拦截处理了。
executeChain这个方法是处理的方法。
我们先获取处理的类FilterChain。就是通过请求路径来取对应的FilterChain。当然这个我们也可以自定义。

 

11.依次会走ProxiedFIlterChain.doFilter OncePerRequestFilter.doFIlter AdviceFilter.doFilterInternal

进入AdviceFilter.doFilterInternal方法执行preHandle(request,response)

 通过登录的链接拦截到后,执行对应过滤器的过滤方法。InvalidRequestFilter中的 isAccessAllowed。

 13.如果返回结果为false则执行onAccessDenied方法

 13。继续执行 executeChain(request, response, chain)方法。

14.同上,依次通过ProxiedFIlterChain.doFilter OncePerRequestFilter.doFIlter AdviceFilter.doFilterInternal

进入AdviceFilter.doFilterInternal方法执行preHandle(request,response),经过PathMatchingFilter进入AccessControlFilter中的onPreHandle方法

 15.进入到AuthenticatingFilter的isAccessAllowed方法

 16.如果isAccessAllowed方法为false进入到AuthenticatingFilter的onAccessDenied

 17.进入saveRequestAndRedirectToLogin方法

 18.进入AccessControlFilter的saveRequest方法

 19.进入WebUtils中

 20.进入getSession方法中

 继续跟进

 进入AbstractNativeSessionManager

 进入AbstractValidatingSessionManager的createSession方法

 接着进入DefaultSessionManager中的createSession方法

 调用DefaultSessionManager的create方法

 调用AbstractSessionDAO的create方法

 执行doCreate方法,进入RedisSessionDao中的doCreate方法

 其中saveSession方法是真正的存储操作

 进行session的赋值和更新

 此时session的保存就已经完成了。

5.2会话创建流程(第一次请求为登录时)

 session的分析切入点是在:DefaultSecurityManger的login方法中。

 继续DefaultSecurityManger

 DefaultSecurityManger的createSubject方法

 转移到DefaultSubjectDAO调用DefaultSubjectDAO.save(subject)方法

  调用DefaultSubjectDAO.saveToSession(subject)方法

 调用DefaultSubjectDAO的mergePrincipals方法

 转移到DelegatingSubject调用DelegatingSubject的getSession

 进入getSession方法中

 继续跟进

 进入AbstractNativeSessionManager

 进入AbstractValidatingSessionManager的createSession方法

 接着进入DefaultSessionManager中的createSession方法

 调用DefaultSessionManager的create方法

 SessionDao

 调用AbstractSessionDAO的create方法

 执行doCreate方法,进入RedisSessionDao中的doCreate方法

 其中saveSession方法是真正的存储操作

 回到DefaultSubjectDAO中,进行session属性的填充和更新缓存中的session。

跟进去进入到了Session的实现类ProxiedSession的session.setAttribute方法中

 继续跟进,进入到了Session的另一个实现类DelegatingSession的setAttribute方法中

 回到了SessionManager的子类AbstractNativeSessionManager的setAttribute方法中

进入onChange方法

 再次回到DefaultSubjectDAO中执行mergeAuthenticatuonState方法

 进入该方法

 

 此时,session的创建、赋值和存储已完成。

5.2会话的刷新和过期校验。

SimpleSession是shiro完完全全的自己实现,是shiro对session的一种拓展;实现了ValidatingSession接口,具有自我校验的功能;一般不对外暴露,暴露的往往是他的代理。

1.刷新

ShiroFilter的类图如下:

流程如下:

1.进入AbstractShiroFilter中的doFilterInternal中

 2.执行updateSessionLastAccessTime方法

此时session的刷新已经完成。

2.过期

之所以进行session校验是因为在每次发起请求后经过AbstractShiroFilter.doFilterInternal方法时,会通过Cookie中所携带的sessionId来进行session获取。如果session过期了,会重定向到登录页面,以此来进行会话的管理。sessionId是在第一次请求成功之后保存在客户端的。

启动校验定时任务

在AbstractValidatingSessionManager中createSession方法在调用doCreateSession方法之前调用enableSessionValidationIfNecessary()方法,代码如下

定时任务默认是每60分钟执行一次,第一次执行是在定时器初始化完成60分钟后执行。

在定时任务间隔期间,session的操作通过代理之后,都会来到sessionManager,sessionManager通过处理之后再到SimpleSession;AbstractNativeSessionManager中将session操作放给SimpleSession之前,都会调用lookupSession方法,跟进lookupSession你会发现,里面也有session的校验,如下图所示:

 所以session的校验,不只是定制任务在执行,很多session的操作都有做session的校验。

posted @ 2022-03-28 14:03  我所理解的代码  阅读(275)  评论(0)    收藏  举报