IT小栈

  • 主页
  • Java基础
  • RocketMQ
  • Kafka
  • Redis
  • Shiro
  • Spring
  • Spring Boot
  • Spring Cloud
  • 资料链接
  • 关于
所有文章 友链

IT小栈

  • 主页
  • Java基础
  • RocketMQ
  • Kafka
  • Redis
  • Shiro
  • Spring
  • Spring Boot
  • Spring Cloud
  • 资料链接
  • 关于

Shiro中Subject与Session

2019-07-30

上面几节我们分析了过滤器链执行的过程,其中涉及到Subject和Session没有进行分析,本节我们重点分析下。

补充知识:传统的session就是servlet的httpsession

当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否包含了一个session标识(即sessionId),如果已经包含一个sessionId则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。如果客户请求不包含sessionId,则为此客户创建一个session并且生成一个与此session相关联的sessionId,这个session id将在本次响应中返回给客户端保存。JSESSION是默认的的名字

在《Shiro工作原理》一文中我们分析了其过程其中分析了ShiroFilterFactoryBean为什么是一个过滤器,在创建过滤器createInstance()的方法中返回了一个SpringShiroFilter对象。请求过来时都会执行SpringShiroFilter中的doFilter(),我们发现该过滤器没有该方法,那肯定调用的是父类的。

SpringShiroFilter是ShiroFilterFactoryBean的内部类属于,继承AbstractShiroFilter,其doFilter方法在父类中,OncePerRequestFilter的doFilter()方法是final所以子类不能重写doFilter(),这才是业务核心代码所在。查看其源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
if ( request.getAttribute(alreadyFilteredAttributeName) != null ) {
log.trace("Filter '{}' already executed. Proceeding without invoking this filter.", getName());
filterChain.doFilter(request, response);
} else //noinspection deprecation
if (/* added in 1.2: */ !isEnabled(request, response) ||
/* retain backwards compatibility: */ shouldNotFilter(request) ) {
log.debug("Filter '{}' is not enabled for the current request. Proceeding without invoking this filter.",
getName());
filterChain.doFilter(request, response);
} else {
// Do invoke this filter...
log.trace("Filter '{}' not yet executed. Executing now.", getName());
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);

try {
doFilterInternal(request, response, filterChain);
} finally {
// Once the request has finished, we're done and we don't
// need to mark as 'already filtered' any more.
request.removeAttribute(alreadyFilteredAttributeName);
}
}
}

核心方法doFilterInternal()

SpringShiroFilter的父类是AbstractShiroFilter自然执行其doFilterInternal()

上次没有分析Subject对象创建的过程,这次重点分析一下,在doFilterInternal中,可以看到对ServletRequest和ServletReponse进行了包装。除此之外,还把包装后的request/response作为参数,创建Subject,这个subject其实是代理类DelegatingSubject。
先看包装后的ServletRequest和ServletReponse

ServletReponse没有什么特殊了就不分析了,向下看代码,创建Subejct过程

我们重点分析session创建。

把创建Session过程说完后,再回到此处是要记着不会去创建一个Session。但是我们可以来看下是如何创建Session的,整体三大步骤,先创建一个SessionContext,然后根据SessionContext来创建Session,最后是装饰Session

通过上面的代码分析我们知道,在创建Subejct的时候没有创建Session,这是为什么呢,因为在创建Subject的时候还没有用户信息,只有当subject.login(token)的时候会获取用户信息,才能将用户信息放入session中。那我们具体分析下。

向下看代码,execute将方法的调用者subject存入到当前Thread的线程本地存储中

  • 虽然当前的实际类型是WebDelegatingSubject,而execute实际是定义在其基类DelegatingSubject中的,而且WebDelegatingSubject并未对其进行重载。

  • DelegatingSubject类对execute方法的实现则是将其委托给了专门的SubjectCallable<V>。

  • 正是在SubjectCallable<V>类中,Shiro将本次构造的Subject实例存放到了当前Thread的线程本地存储中;也就是将该Subject实例与当前Thread进行绑定。

  • 还可以看到Shiro对于ThreadLocal<T>的使用方式是将其封装为对自定义的ThreadContext的调用。关于ThreadContext,其显式绑定的就两个实例:Subject和SecurityManager 。这个观察其定义的bind方法就知晓了。

我们分析一下SecurityUtils.getSubject()方法

本文作者: 顾 明 训
本文链接: https://www.itzones.cn/2019/07/30/Shiro中Subject与Session/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!
  • shiro源码分析
  • shiro

扫一扫,分享到微信

微信分享二维码
Java代码编译过程
Shiro授权验证
目录,不存在的…
© 2020 IT小栈
载入天数...载入时分秒... || 本站总访问量次 || 本站访客数人次
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链

tag:

  • jvm
  • Java基础
  • kafka HW
  • kafka Leader Epoch
  • kafka
  • kafka位移主题
  • kafka位移提交
  • kafka副本机制
  • kafka ISR
  • zookeeper
  • kafka消息丢失
  • kafka日志存储
  • kafka Log Clean
  • kafka Log Compaction
  • kafka消费位移设置
  • kafka Rebalance
  • kafka分区算法
  • kafka生产者拦截器
  • kafka SASL/SCRAM
  • kafka ACL
  • redis
  • redis Ziplist
  • redis Hashtable
  • redis LinkedList
  • redis QuickList
  • redis intset
  • redis String
  • redis SDS
  • redis SkipList
  • redisDb
  • redisServer
  • redis 简介
  • Redis Cluster
  • 主从同步
  • RocketMQ高可用HA
  • 事务消息
  • 内存映射
  • MMAP
  • 同步刷盘
  • 异步刷盘
  • 消息存储文件
  • RocketMQ安装
  • 延迟消息
  • RocketMQ入门
  • 推拉模式
  • PushConsumer
  • 消费结果处理
  • rebalance
  • RocketMQ权限控制
  • RocketMQ ACL
  • 消息过滤
  • 消息重试
  • 消费位置
  • 集群消费
  • 广播消费
  • 运维命令
  • shiro源码分析
  • shiro入门
  • IOC和DI
  • Spring创建Bean
  • Bean生命周期
  • Sping属性注入
  • 异常
  • SpringMVC
  • springCloud
  • Eureka

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 我的OSCHINA
  • 我的CSDN
  • 我的GITHUB
  • 一生太水