前言

  开心一刻

    开学了,表弟和同学因为打架,老师让他回去叫家长。表弟硬气的说:不用,我打得过他。老师板着脸对他说:和你打架的那位同学已经回去叫家长了。表弟犹豫了一会依然硬气的说:可以,两个我也打得过。老师:......

  路漫漫其修远兮,吾将上下而求索!

  github:https://github.com/youzhibing

  码云(gitee):https://gitee.com/youzhibing

前情回顾

  大家还记得上篇博文讲了什么吗,我们来一起简单回顾下:

    HttpServletRequestWrapper是HttpServletRequest的装饰类,我们通过继承HttpServletRequestWrapper来实现我们自定义的HttpServletRequest:CustomizeSessionHttpServletRequest,重写CustomizeSessionHttpServletRequest的getSession,将其指向我们自定义的session。然后通过Filter将CustomizeSessionHttpServletRequest添加到Filter chain中,使得到达Servlet的ServletRequest是我们的CustomizeSessionHttpServletRequest。

  今天不讲session共享,我们先来看看shiro的session创建

SecurityManager

  SecurityManager,安全管理器;即所有与安全相关的操作都会与SecurityManager交互;它管理着所有Subject,所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;SecurityManager是shiro的核心,它负责与shiro的其他组件进行交互,类似SpringMVC中的DispatcherServlet或Struts2中的FilterDispatcher。

  我们在使用shiro的时候,首先都会先初始化SecurityManager,然后往SecurityManager中注入shiro的其他组件,像sessionManager、realm等。我们的spring-boot-shiro中初始化的是DefaultWebSecurityManager,如下

@Bean
public SecurityManager securityManager(AuthorizingRealm myShiroRealm, CacheManager shiroRedisCacheManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setCacheManager(shiroRedisCacheManager);
securityManager.setRememberMeManager(cookieRememberMeManager());
securityManager.setRealm(myShiroRealm);
return securityManager;
}

  SecurityManager类图

    结构如下,认真看看,注意看下属性

    顶层组件SecurityManager直接继承了SessionManager且提供了SessionsSecurityManager实现,SessionsSecurityManager直接把会话管理委托给相应的SessionManager;SecurityManager的默认实现:DefaultSecurityManager及DefaultWebSecurityManager都继承了SessionsSecurityManager,也就是说:默认情况下,session的管理由DefaultSecurityManager或DefaultWebSecurityManager中的SessionManager来负责。

    DefaultSecurityManager

      默认安全管理器,用于我们的javaSE安全管理,一般而言用到的少,但我们需要记住,万一哪次有这个需求呢。

      我们来看下他的构造方法

      默认的sessionManager是DefaultSessionManager,DefaultSessionManager具体详情请看下文。

    DefaultWebSecurityManager

      默认web安全管理器,用于我们的web安全管理;一般而言,我们的应用中初始化此安全管理器。

      我们来看看其构造方法

public DefaultWebSecurityManager() {
super(); // 会调用SessionsSecurityManager的构造方法,实例化DefaultSessionManager
((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(new DefaultWebSessionStorageEvaluator());
this.sessionMode = HTTP_SESSION_MODE;
setSubjectFactory(new DefaultWebSubjectFactory());
setRememberMeManager(new CookieRememberMeManager());
setSessionManager(new ServletContainerSessionManager()); // 设置sessionManager,替换掉上面的DefaultSessionManager
}

      可以看出此时的sessionManager是ServletContainerSessionManager,ServletContainerSessionManager具体详情请看下文。

    由此可知默认情况下,DefaultSecurityManager会将session管理委托给DefaultSessionManager,而DefaultWebSecurityManager则将session管理委托给ServletContainerSessionManager。

    我们可以通过继承DefaultSecurityManager或DefaultWebSecurityManager来实现自定义SecurityManager,但一般而言没必要,DefaultSecurityManager和DefaultWebSecurityManager基本能满足我们的需要了,我们根据需求二选其一即可。无论DefaultSecurityManager还是DefaultWebSecurityManager,我们都可以通过setSessionManager方法来指定sessionManager,如果不指定sessionManager的话就用的SecurityManager默认的sessionManager。

SessionManager

  shiro提供了完整的会话管理功能,不依赖底层容器,JavaSE应用和JavaEE应用都可以使用。会话管理器管理着应用中所有Subject的会话,包括会话的创建、维护、删除、失效、验证等工作。

  SessionManager类图

      DefaultSessionManager

      DefaultSecurityManager默认使用的SessionManager,用于JavaSE环境的session管理。

      通过上图可知(结合SecurityManager类图),session创建的关键入口是SessionsSecurityManager的start方法,此方法中会将session的创建任务委托给具体的SessionManager实现。

      DefaultSessionManager继承自AbstractNativeSessionManager,没用重写start方法,所以此时AbstractNativeSessionManager的start方法会被调用,start方法如下

public Session start(SessionContext context) {
Session session = createSession(context); // 创建session,类型是SimpleSession
applyGlobalSessionTimeout(session); // 设置session的timeout,也就是有效时间,默认30分钟
onStart(session, context);
notifyStart(session); // 通知session监听器
//Don't expose the EIS-tier Session object to the client-tier:
return createExposedSession(session, context); // 创建对外暴露的session,SimpleSession的代理;类型是DelegatingSession,持有sessionManager的引用
}

      跟进createSession(),代码入下

protected Session createSession(SessionContext context) throws AuthorizationException {
enableSessionValidationIfNecessary(); // 初次被调用时启动定时任务来验证session,具体请看下篇博客
return doCreateSession(context); // 真正创建session
}

      其中doCreateSession方法完成session的创建,doCreateSession方法大家可以自行去跟下,我在这总结一下:       

        创建session,并生成sessionId,session是shiro的SimpleSession类型,sessionId采用的是随机的UUID字符串;
        sessionDAO类型是MemorySessionDAO,session存放在sessionDAO的private ConcurrentMap<Serializable, Session> sessions;属性中,key是sessionId,value是session对象;
        除了MemorySessionDAO,shiro还提供了EnterpriseCacheSessionDAO,具体两者有啥区别请看我的另一篇博客讲解。

    ServletContainerSessionManager

      DefaultWebSecurityManager默认使用的SessionManager,用于Web环境,直接使用的Servlet容器的会话,具体实现我们往下看。

      ServletContainerSessionManager实现了SessionManager,并重写了SessionManager的start方法,那么我们从ServletContainerSessionManager的start方法开始来看看session的创建过程,如下图

      shiro有自己的HttpServletSession,HttpServletSession持有servlet的HttpSession的引用,最终对HttpServletSession的操作都会委托给HttpSession(装饰模式)。那么此时的session是标准servlet容器支持的HttpSession实例,它不与Shiro的任何与会话相关的组件(如SessionManager,SecurityManager等)交互,完全由servlet容器管理。

    DefaultWebSessionManager

      用于Web环境,可以替换ServletContainerSessionManager,废弃了Servlet容器的会话管理;通过此可以实现我们自己的session管理;

      从SessionManager类图可知,DefaultWebSessionManager继承自DefaultSessionManager,也没有重写start方法,那么创建过程还是沿用的AbstractNativeSessionManager的start方法;如果我们没有指定自己的sessionDao,那么session还是存在MemorySessionDAO的ConcurrentMap<Serializable, Session> sessions中,具体可以看上述中的DefaultSessionManager。

      通过DefaultWebSessionManager实现session共享,请点此处

总结

  SecurityManager和SessionManager的类图需要认真看看;

  Subject的所有交互都会委托给SecurityManager;SecurityManager是shiro的核心,它负责与shiro的其他组件进行交互,类似SpringMVC中的DispatcherServlet或Struts2中的FilterDispatcher;

  SecurityManager会将session管理委托给SessionManager;SessionsSecurityManager的start方法中将session的创建委托给了具体的sessionManager,是创建session的关键入口。
  shiro的SimpleSession与HttpServletSession
    HttpServletSession只是servlet容器的session的装饰,最终还是依赖servlet容器,是shiro对servlet容器的session的一种支持;
    而SimpleSession是shiro完完全全的自己实现,是shiro对session的一种拓展。但SimpleSession不对外暴露,我们一般操作的是SimpleSession的代理:DelegatingSession,或者是DelegatingSession的代理:StoppingAwareProxiedSession;对session的操作,会通过一层层代理,来到DelegatingSession,DelegatingSession将session的操作转交给sessionMananger,sessionManager通过一些校验后,最后转交给SimpleSession处理。

参考

  《跟我学shiro》

shiro源码篇 - shiro的session创建,你值得拥有的更多相关文章

  1. shiro源码篇 - shiro的filter,你值得拥有

    前言 开心一刻 已经报废了一年多的电脑,今天特么突然开机了,吓老子一跳,只见电脑管家缓缓地出来了,本次开机一共用时一年零六个月,打败了全国0%的电脑,电脑管家已经对您的电脑失去信心,然后它把自己卸载了 ...

  2. shiro源码篇 - shiro的session共享,你值得拥有

    前言 开心一刻 老师对小明说:"乳就是小的意思,比如乳猪就是小猪,乳名就是小名,请你用乳字造个句" 小明:"我家很穷,只能住在40平米的乳房" 老师:" ...

  3. shiro源码篇 - shiro认证与授权,你值得拥有

    前言 开心一刻 我和儿子有个共同的心愿,出国旅游.昨天儿子考试得了全班第一,我跟媳妇合计着带他出国见见世面,吃晚饭的时候,一家人开始了讨论这个.我:“儿子,你的心愿是什么?”,儿子:“吃汉堡包”,我: ...

  4. shiro源码篇 - shiro的session的查询、刷新、过期与删除,你值得拥有

    前言 开心一刻 老公酷爱网络游戏,老婆无奈,只得告诫他:你玩就玩了,但是千万不可以在游戏里找老婆,不然,哼哼... 老公嘴角露出了微笑:放心吧亲爱的,我绝对不会在游戏里找老婆的!因为我有老公! 老婆: ...

  5. shiro源码篇 - 疑问解答与系列总结,你值得拥有

    前言 开心一刻 小明的朋友骨折了,小明去他家里看他.他老婆很细心的为他换药,敷药,然后出去买菜.小明满脸羡慕地说:你特么真幸福啊,你老婆对你那么好!朋友哭得稀里哗啦的说:兄弟你别说了,我幸福个锤子,就 ...

  6. Shiro源码解析-Session篇

    上一篇Shiro源码解析-登录篇中提到了在登录验证成功后有对session的处理,但未详细分析,本文对此部分源码详细分析下. 1. 分析切入点:DefaultSecurityManger的login方 ...

  7. 源码分析shiro认证授权流程

    1. shiro介绍 Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户“登录”: 授权 - 访问控制: 密码加密 ...

  8. Shiro源码分析之SecurityManager对象获取

    目录 SecurityManager获取过程 1.SecurityManager接口介绍 2.SecurityManager实例化时序图 3.源码分析 4.总结 @   上篇文章Shiro源码分析之获 ...

  9. Shiro 源码分析

    http://my.oschina.net/huangyong/blog/215153 Shiro 是一个非常优秀的开源项目,源码非常值得学习与研究. 我想尝试做一次 不一样 的源码分析:源码分析不再 ...

随机推荐

  1. wcf生成客户端代理类步骤及语句

    通过svcutil.exe工具生成客户端代理类和客户端的配置文件 .在运行中输入cmd打开命令行 ()cd C:\Program Files (x86)\Microsoft SDKs\Windows\ ...

  2. 微信小程序的自定义插件

    第一步,创建一个页面和普通页面一样 第二不,在这个页面上进行对json配置, "component":true 第三不在需要插入的页面中进行设置 插入标签 <dialog i ...

  3. 2019浙大校赛--G--Postman(简单思维题)

    一个思维水题 题目大意为,一个邮递员要投递N封信,一次从邮局来回只能投递K封.求最短的投递总距离.需注意,最后一次投递后无需返回邮局. 本题思路要点: 1.最后一次投递无需返回邮局,故最后一次投递所行 ...

  4. Atomic in Redis

    Since Redis is single-threaded, everything is atomic.

  5. qscoj 喵哈哈村的打印机游戏 区间dp

    点这里去看题 区间dp ,dp[l][r][d]代表从l到r的区间底色为d,具体看代码 第一次见到区间dp...两个小时对着敲了五遍终于自己敲懂了一遍ac #include<bits/stdc+ ...

  6. 两个VirtualBox版本装的语言不一样?

    两个VirtualBox版本装的语言不一样? 1.这个是我用的两个版本的VirtualBox. 2.用这个 VirtualBox-4.3.20-96997-Win.exe安装的时候,一直是英文. 3. ...

  7. Visual Studio 常见的快捷键

    “Ctrl + -”               回到上一个光标位置 “Ctrl + Shift + -”                前进到下一个光标位置 “Ctrl + C”           ...

  8. mysql中删除重复记录,只保留一条

    表结构如下: mysql> desc test1; +--------------+------------------+------+-----+---------+------------- ...

  9. day_8文件的操作

    首先昨天讲的内容有 类型转换 1:数字类型: int ()  bool()  float() 2:str 与int:    int('10') | int('-10') | int('0') | fl ...

  10. 使用python访问网络上的数据

    这两天看完了Course上面的: 使用 Python 访问网络数据 https://www.coursera.org/learn/python-network-data/ 写了一些作业,完成了一些作业 ...